无限循环的 Java 未知原因

Java unknown cause for infinite loop

提问人:jllangston 提问时间:7/11/2023 更新时间:7/11/2023 访问量:89

问:

我有一个代码结果,我无法在发送电子邮件的 Java 11 代码中解释。

我正在使用javax邮件包:

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

代码如下:

Properties props = System.getProperties();
props.put("mail.smtp.host", smtpHost);
Session session = Session.getInstance(props);

int nMaxTries = 5;
int nTries = 0;
boolean success = false;

while (!success || nTries >= nMaxTries) {
    try {
        MimeMessage msg = new MimeMessage(session);
        //set message headers
        msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
        msg.addHeader("format", "flowed");
        msg.addHeader("Content-Transfer-Encoding", "8bit");

        msg.setFrom(new InternetAddress(fromEmail, from));
        msg.setSubject(subject, "UTF-8");
        msg.setContent(body, "text/html");
        msg.setSentDate(new Date());
        msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));

        System.out.println("Message is ready");
        Transport.send(msg);

        System.out.println("EMail Sent Successfully!!");
        success = true;
    } catch (Exception e) {
        e.printStackTrace();
        nTries++;
    }
}

我注意到有时电子邮件会失败,因此重试。这使用将输出通过管道传递到日志的 cron 进程运行。这已经工作了几个星期。今天早上,我收到了近 400,000 封电子邮件。我在日志中一遍又一遍地看到这一点:

Message is ready
EMail Sent Successfully!!
Message is ready
EMail Sent Successfully!!
Message is ready
EMail Sent Successfully!!
Message is ready
EMail Sent Successfully!!
Message is ready

这是一个单线程进程。看到这里,我意识到我可以增加循环中的计数器,而不仅仅是 catch 语句,这样这些无限循环就会停止。谁能解释一下 while 循环如何无法完成的逻辑?

谢谢!

java while-loop 无限循环

评论

4赞 Federico klez Culloca 7/11/2023
&& nTries < nMaxTries
3赞 Bentaye 7/11/2023
这意味着永不满足。w 可以看到 success 设置为 true,因此存在问题!success || nTries >= nMaxTries|| nTries >= nMaxTries
2赞 Scott Hunter 7/11/2023
这将是学习如何使用调试器的好时机。

答:

0赞 NeebletWorm 7/11/2023 #1

错误出在 while 循环中。

您有两个条件。

第一个是“继续,而成功是”假的” 第二个是“当 nTries 等于或优于 nMaxTries 时继续”

现在,如果第一秒或第二秒是正确的(您使用了 ||),则将执行 while 指令中的代码。

我怀疑的是,电子邮件在未知的时间段内发送了 5 次失败(因此将变量 nTries 递增为 5)并导致循环,因为第二个条件始终为真。(nTries >= nMaxTries)。

为了纠正该问题,您需要执行以下测试:

!success && nTries < nMaxTries

评论

0赞 Community 7/14/2023
您的答案可以通过其他支持信息进行改进。请编辑以添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以在帮助中心找到有关如何写出好答案的更多信息。
0赞 Guillem Chesa 7/11/2023 #2

循环是错误的。它应该是这样的:while

while (!success && nTries < nMaxTries)

否则,两者都从 0 开始,并且无论增加多少次,条件始终为 true,并且如果邮件正确发送,操作员仍将考虑 和 为 true 之间的比较,即使为 false。nTriesnMaxTries>=nTries||nTriesnMaxTries!success

0赞 Aditya Ajmera 7/11/2023 #3

让我们假设一个场景,在前 5 次中,发送消息失败(发生异常),因此您的变量现在等于 并且现在您已成功发送消息,因此,但您使用了 OR 条件,因此它将检查第二个条件是否为 true。所以总的来说,表达成为真的。由于此条件永远不会改变,而循环现在被卡住并已成为无限循环。nTriesnMaxTriessuccess=truenTries >= nMaxTries!success || nTries >= nMaxTries

3赞 WJS 7/11/2023 #4

如前所述,使用

!success && nTries < nMaxTries

但是,忘记测试成功布尔值,并在发送电子邮件时跳出循环。

while (nTries < nMaxTries) {
    try {
        MimeMessage msg = new MimeMessage(session);
        //set message headers
        msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
        msg.addHeader("format", "flowed");
        msg.addHeader("Content-Transfer-Encoding", "8bit");

        msg.setFrom(new InternetAddress(fromEmail, from));
        msg.setSubject(subject, "UTF-8");
        msg.setContent(body, "text/html");
        msg.setSentDate(new Date());
        msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));

        System.out.println("Message is ready");
        Transport.send(msg);

        System.out.println("EMail Sent Successfully!!");
        success = true;    // keep for final status
        break;             // terminate the loop here.
    } catch (Exception e) {
        e.printStackTrace();
        nTries++;
    }
}

评论

0赞 WJS 7/11/2023
另外,这里是必需的课程吗?没有注意到导入,但已过时,除非需要向后兼容性,否则建议使用 java.time 包中的类。Date()java.util.Date