Java 启动执行计算的线程或SwingWorker时Swing伪块

Java 启动执行计算的线程或SwingWorker时Swing伪块,java,multithreading,swing,swingworker,Java,Multithreading,Swing,Swingworker,我有一个非常简单的应用程序,它的行为非常奇怪 这本质上是SwingWorker示例,但当我按下按钮时,GUI的行为就像EDT被阻止一样。我可以同时启动两个,它们并行运行(运行时间几乎相同),但它们运行时菜单仍然冻结。当我使用带有runnable的线程时,会发生完全相同的行为。同样有趣的是,如果循环被Thread.sleep替换,GUI会正常工作 有什么想法吗 public class DummyFrame extends JFrame { public DummyFrame()

我有一个非常简单的应用程序,它的行为非常奇怪

这本质上是SwingWorker示例,但当我按下按钮时,GUI的行为就像EDT被阻止一样。我可以同时启动两个,它们并行运行(运行时间几乎相同),但它们运行时菜单仍然冻结。当我使用带有runnable的线程时,会发生完全相同的行为。同样有趣的是,如果循环被Thread.sleep替换,GUI会正常工作

有什么想法吗

public class DummyFrame extends JFrame {

        public DummyFrame() {
                JMenuBar bar = new JMenuBar();
                JMenu menu = new JMenu("File");
                menu.add(new JMenuItem("TEST1"));
                menu.add(new JMenuItem("Test2"));
                bar.add(menu);
                setJMenuBar(bar);

                JButton button = new JButton("FOOBAR");
                button.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent arg0) {
                                final long start = System.currentTimeMillis();

                                SwingWorker<Void, Integer> testTask = new SwingWorker<Void, Integer>() {        
                                        @Override
                                        protected Void doInBackground()
                                        throws Exception {
                                                int k = 0;
                                                for (int i=0; i<200000; i++) {
                                                        for (int j=0; j<100000; j++) {
                                                                if (i==j && i%10000 == 0)
                                                                        k++;
                                                        }
                                                }
                                                System.out.println(k+" "+(System.currentTimeMillis()-start));
                                                return null;
                                        }
                                };
                                testTask.execute();
                        }

                });
                getContentPane().add(button);
                pack();
        }

        public static void main(String[] args) {
                SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                                DummyFrame f = new DummyFrame();
                                f.setVisible(true);     
                        }
                });
        }
}
公共类DummyFrame扩展了JFrame{
公共DummyFrame(){
JMenuBar=新的JMenuBar();
JMenu菜单=新JMenu(“文件”);
添加(新的JMenuItem(“TEST1”));
添加(新的JMenuItem(“Test2”));
添加(菜单);
setJMenuBar(bar);
JButton按钮=新JButton(“FOOBAR”);
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件arg0){
最终长启动=System.currentTimeMillis();
SwingWorker testTask=新SwingWorker(){
@凌驾
受保护的Void doInBackground()
抛出异常{
int k=0;

对于(int i=0;i我认为问题在于,代码可以很容易地使用100%的CPU。如果每个核心运行一个线程,那么就没有太多的空间来运行其他线程。

问题在于VM的线程实现。规范没有指定如何实现。Java线程应该映射到本机Windows threads,然后使用Windows调度程序共享时间片。目前尚不清楚是否确实发生了这种情况,所有官方文档都只支持Solaris上运行的线程信息

我认为主要的问题来自线程抢占的实现细节。这可能是由于JVM和本机操作系统之间的编译代码优化和抢占控制的组合造成的。JVM可以使用方法调用作为抢占线程的点,我认为这里的部分问题是t您正在一个接一个地调用。如果您用函数调用来分解它们,它在我的计算机上的性能会更好。我在Windows 7上使用的是1.6.0_23 64位服务器虚拟机

SwingWorker<Void, Integer> testTask = new SwingWorker<Void, Integer>() {

    private int k;

    private void inc() {
        this.k++;
    }

    private void innerLoop(int i) {
        for (int j=0; j<100000; j++) {
            if (i==j && i%10000 == 0)
                this.inc();
        }
    }

    @Override
    protected Void doInBackground()
    throws Exception {
        System.out.println("Started");
        for (int i=0; i<200000; i++) {
            this.innerLoop(i);
        }
        System.out.println(k+" "+(System.currentTimeMillis()-start));
        return null;
    }
};
SwingWorker testTask=新SwingWorker(){
私人INTK;
私人void公司{
这个是.k++;
}
私有void内部循环(int i){

对于(int j=0;j更具体地说,我认为JVM进程中有一个线程是这样运行的,这就是为什么它不一定会让整个系统崩溃的原因——只是JVM在该进程中运行。即使你不使用
SwingWorker
——只使用普通的
线程
——你也可能会遇到同样的问题处理这个问题的有效方法是在紧密循环中调用
Thread.yield()
,这将给其他线程运行的机会。