Swing在生成单独的线程时冻结

时间:2012-06-01 03:27:51

标签: java swing

为什么这段代码会冻结我的Swing应用程序? Swing组件与InfiniteLoop线程位于一个单独的线程中。如果我在每次打印之前在run()方法中引入sleep,那么程序运行正常。有人有任何线索吗?

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");
         }
    }
}

1 个答案:

答案 0 :(得分:3)

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

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

这里有an article描述了这一点。

作为一种潜在的改进:invokeLater()调用最终可能会将runnable放在一个永远不会出队的队列中,因为你的后台线程占用了所有的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界面是否仍然保持响应?