4

为什么这段代码会冻结我的 Swing 应用程序?Swing 组件位于与我的 InfiniteLoop 线程不同的线程中。如果我在每次打印之前在 run() 方法中引入睡眠,那么程序可以正常工作。有没有人有任何线索?

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI(); // <-- creates the swing frame and component
        }
    });

    Thread t = new Thread(new InfiniteLoop()); 
    t.start();
}

public class InfiniteLoop implements Runnable
{
    private static Logger logger = Logger.getLogger(InfiniteLoop.class);
    public void run()
    {
         while(true)
         {
              log.info("test");
         }
    }
}
4

1 回答 1

3

这里的答案与 Java 的线程调度实现有关(或者更确切地说,是您平台的 Java 线程调度实现的细节)。大多数 Java 线程实现最终都会运行给定的线程(以给定的优先级),直到线程进入等待条件。然后运行该优先级的下一个线程,等等......请注意,JVM 规范没有指定确切的行为 - 这取决于 JVM 实现者来决定。

您可能需要考虑降低工作线程的优先级,而不是将睡眠插入您的工作线程。让线程休眠会起作用,但是要记住这样做很麻烦,并且它会迫使工作线程花费比其他方式更长的时间来做事。如果您确实插入了睡眠调用,请执行 0 毫秒(这足以释放线程,但如果没有其他线程处于活动状态,则应立即返回执行)。

这是一篇文章,对此进行了一些描述。

作为一个潜在的改进:invokeLater() 调用可能最终将可运行对象放入一个队列中,因为您的后台线程正在占用所有 CPU,所以该队列永远没有机会出队。一个有趣的实验是将后台线程的启动移动到 Runnable 中——这将使 EDT 有机会在后台线程开始消耗 CPU 之前进行初始化。

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI(); // <-- creates the swing frame and component

            Thread t = new Thread(new InfiniteLoop()); 
            t.start();
        }
    });

}

甚至:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            Thread t = new Thread(new InfiniteLoop()); 
            t.start();

            createAndShowGUI(); // <-- creates the swing frame and component
        }
    });

}

我实际上会对这个结果感兴趣(虽然没有足够的兴趣来实际测试它:-))。我在网上看到的一些参考资料说 EDT 默认以更高的优先级运行(在这种情况下,EDT 本身不应该经历饥饿)。如果从 EDT 内部启动后台线程,Swing 界面是否保持响应?

于 2012-06-01T04:04:30.693 回答