为什么这个break语句不起作用?

6

I have the following code:

public void post(String message) {
    final String mess = message;
    (new Thread() {
        public void run() {
            while (true) {
                try {
                    if (status.equals("serviceResolved")) {
                        output.println(mess);
                        Game.log.fine("The following message was successfully sent: " + mess);
                        break;
                    } else {
                        try {Thread.sleep(1000);} catch (InterruptedException ie) {}
                    }
                } catch (NullPointerException e) {
                    try {Thread.sleep(1000);} catch (InterruptedException ie) {}
                }
            }
        }
    }).start();
}

在我的日志文件中,我发现了很多类似这样的行:

The following message was successfully sent: blablabla
The following message was successfully sent: blablabla
The following message was successfully sent: blablabla
The following message was successfully sent: blablabla

我的程序没有响应。

我觉得break命令不起作用。可能的原因是什么?

有趣的是,这种情况并非总是发生。有时我的程序可以正常工作,有时会出现上述问题。


顺便说一句:你可以将两个Thread.sleep()行提取出来,在最外层的try/catch之后执行单个行。 - Jason S
2
捕获NullPointerException似乎不是一个好主意(它是否应该检查status == null - 如果是,请检查status是否为null)。而InterruptedException应该被设置为退出循环(虽然我不喜欢线程中断,但它确实存在,因此应该处理)。/ 另外,您可以将参数final化,这样就不需要复制mess了。 - Tom Hawtin - tackline
3
我猜测post方法被频繁调用,问题不仅限于这段代码。程序停止响应是因为它产生了许多线程(并非所有线程的状态都为serviceResolved)。 - Yishai
1
我至少会移除对 NullPointerException 的捕获。你永远不应该捕获 RuntimeException。它们表示代码/程序员错误,应通过正确重写代码来修复,而不是通过捕获它们来解决。无论如何,永远不要忽略/吞噬已捕获的异常,总是记录它们。 - BalusC
无法复现。如果我将“Game.log”更改为“System.out”,则可以正常工作。 - Bozho
显示剩余4条评论
5个回答

4

这一行成功了吗:

output.println(mess);

但是这行代码抛出了一个空指针异常:
Game.log.fine(...

在这种情况下,您将在控制台上看到输出,但是永远不会执行break语句。 Game.log 是否为null?

1
这不可能是这样的,因为他报告看到了来自Game.log行的以下消息已成功发送: - polygenelubricants
1
我有什么遗漏吗?OP说他正在将输出记录到日志中,这意味着“Game.log”不能为null... - Sam Holder
我也将其视为一个教训,尽量缩小 try 块的范围,以使 catches 更有意义。 - Matthew T. Staebler
我原以为“在日志中看到”可以宽泛解释。 - izb
Game.log 可能不为 null,但在成功记录该语句后可能会抛出 NPE。 - whiskeysierra

4

Game.log.fine到底是做什么的?它是否在输出后抛出NullPtrException,或者您是否多次调用post方法?

删除NullPointerException的catch语句,这是不良的编程风格(NullPointerException的发生总是一个编程错误),并在该方法中添加更多的日志消息(或使用调试器)。


3
每次调用post方法时,您都会启动一个新的线程。我认为这个方法是没问题的,但调用程序有问题。

可能应该使用一个队列,配合一个线程/执行器任务,该任务只需启动一次并读取队列。 - Jason S
你说得有点对。我有很多行消息,因为上面给出的代码被调用了很多次,而它被调用了很多次是因为我按了提交按钮很多次(当我的程序被冻结时)。而我的程序之所以被冻结,是因为另一个与给定代码无关的愚蠢错误。 - Roman

2

你确定要在NullPointerException上继续吗?如果在循环内部出现它,你可能会一直等待。

如果你确信status最终总是"serviceResolved",那么在if语句中放置一个try...finally,这样即使出现错误,循环仍然会退出:

if (status.equals("serviceResolved")) {
    // No matter what happens next, we have to bail
    try {
        output.println(mess);
        Game.log.fine("The following message was successfully sent: " + mess);
    } finally {
        break;
    }
} else {
    try {Thread.sleep(1000);} catch (InterruptedException ie) {}
}

0
你假设 break 语句不起作用,但实际上可能是你的 post 方法被重复调用了。尝试在方法开头放置另一个日志语句,以查看它被调用的频率。此外,在 while 循环结束之前但 run 方法结束之前放置一个日志语句,以验证 break 是否真正跳出了循环。
我也同意其他帖子中提到的捕获 NullPointerException 是一种代码异味。你应该先检查变量是否为 null

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接