【问题标题】:How to correctly use ExecutorService to manage the number of concurrently running SwingWorkers?如何正确使用 ExecutorService 来管理同时运行的 SwingWorkers 的数量?
【发布时间】:2014-04-30 17:12:07
【问题描述】:

我正在根据需要建立的许多连接生成 SwingWorker。我正在努力做到这一点,以便我设置固定数量的最大并发 SwingWorkers 并且当其中一个完成时启动另一个(或者如果许多人已经完成,则启动许多其他人)。基于http://java.dzone.com/articles/multi-threading-java-swing,我正在像这样设置基本的 SwingWorker:

SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
        @Override
        protected Boolean doInBackground() throws Exception {

                        System.out.println("One SwingWorker just ran! ");
                }

                return true;
        }

        // Can safely update the GUI from this method.
        protected void done() {

                boolean status;
                try {
                        // Retrieve the return value of doInBackground.
                        status = get();
                        statusLabel.setText("Completed with status: " + status);
                } catch (InterruptedException e) {
                // This is thrown if the thread's interrupted.
                } catch (ExecutionException e) {
                // This is thrown if we throw an exception
                // from doInBackground.
                }
        }


};

worker.execute();


现在我不确定如何实现我上面描述的机制。

https://stackoverflow.com/a/8356896/988591 看到我可以使用 ExecutorService 来执行 SwingWorker 的实例,并且这个接口还允许设置线程数:

int n = 20; // Maximum number of threads
ExecutorService threadPool = Executors.newFixedThreadPool(n);
SwingWorker w; //don*t forget to initialize
threadPool.submit(w);

我认为这是我需要的,但我不知道如何将整个事情放在一起(..我对 Java 也很陌生..)。有人可以在实施这个过程中指导我吗?在顶部说我有int totalTask = 100; 也许这只是一些循环的问题,但我似乎找不到任何真正容易理解的例子,我只是还不能完全理解它所以..我会很感激一些帮助!谢谢。


更新:我已经这样设置了 ExecutorService:

ExecutorService executorService = Executors.newFixedThreadPool(500);

for (int i = 0; i < 20 ; i++) {

    executorService.submit(worker); 
    //I tried both...
    //executorService.execute(worker);
}


我已经删除了在上面的 SwingWorker 之后调用的 worker.execute(),但是 控制台的输出只是一个“一个 SwingWorker 刚刚运行!” 行,这是怎么回事?我做错了什么?

【问题讨论】:

  • 正如我在您之前的问题中注意到的那样,仔细考虑同时运行的 SwingWorkers 实例的数量,SwingWorker 是从 Future 初始化的,并且不能保证每个实例都在同一时间结束或在另一个实例启动之前结束(有效对于带有 Thread 的逻辑,但没有错误),带有 Runnable#Thead 的逻辑更好,更容易和舒适,done() 中的 get() 用于捕获可能的异常,而不是用于返回
  • 我对他们在这种情况下完成的顺序不感兴趣。不确定“但没有错误”是什么意思。在我为 SwingWorker done() 和 get() 阅读的所有文档中,它们分别用于发出回调方法,该方法 1) 可以访问 SwingWorker doInBackground() 的返回值和 2) 可以安全地更新 GUI(因为它是自动在 EDT 中推出)。我不确定您是否引用其他 get() 和 done() 方法,我不知道它们是否也用于 Runnable#Thread。
  • 1.你可以get() an exception or returns 2.publish()/setProcess
  • 嘿...我在这里也有同样的经历。但是我所有的摇摆工人都很好,他们完成了这项工作。唯一奇怪的是 done() 方法只调用了一次,就像你经历过的一样。

标签: java swing threadpool executorservice swingworker


【解决方案1】:

你会做这样的事情:

  • 使用固定的线程池启动 executorservice 显示。
  • 在循环中创建您的可运行文件。尽可能多的可运行文件。
  • 您可以拥有 50 个线程和 5000 个可运行对象。 1 50 后
    runnables,无论哪个线程空闲,都会接第 51 个任务,并且
    以此类推。
  • 使用您的 Runnable 调用 executorservice 的 execute 方法。
  • 完成所有操作后,关闭执行器服务。

像这样:

ExecutorService executorService = Executors.newFixedThreadPool(500);

for (long i = 0; i < 1000000; i++) {
    Runnable populator = new YourRunnable();
    executorService.execute(populator);
}
executorService.shutdown();
while(!executorService.isTerminated()){
}

isTerminated 可以用来检查 executorServices 是否真的宕机了。由于即使在调用了 shutdown() 方法之后也可以运行多个执行程序线程(因为它们还没有完成任务),所以 while 循环就像一个等待调用。

还有一个关键:无论你想传递给 ExecutorService 什么,它都必须是一个 Runnable 实现。在您的情况下,您的 SwingWorker 必须是 Runnable。

【讨论】:

  • So.. uhm.. 如何让 SwingWorker 变成 Runnable?
  • 我不应该这样做,但谷歌搜索返回给我这个:greatratrace.blogspot.in/2010/01/…。您可以根据自己的需要进行调整。
  • 我之前确实访问过该页面,但由于布局糟糕,我关闭了它。谢谢你让我重新考虑。
  • 你不会让像布局这样烦人的东西阻止你得到你需要的东西。 :)
  • 我知道,但是将其添加到 6 天的 Java 经验中,您就会明白了。..
【解决方案2】:

这很有趣。使用有限池的 ExecutorService,您只需要随时提交工作人员,并且只有该数量的工作人员会同时并发执行。

我制作了这个小测试应用程序,您可以在其中按下按钮以尽可能快地提交一些工作人员,并且您可以看到在任何给定时间执行的工作人员数量从未高于值numberOfThreads你初始化 ExecutorService 的那个。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class SwingWorkerExecutorTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new SwingWorkerExecutorTest();
            }
        });
    }


    public SwingWorkerExecutorTest()
    {
        JFrame frame = new JFrame("Frame");

        int numberOfThreads = 2; //1 so they are executed one after the other.
        final ExecutorService threadPool = Executors.newFixedThreadPool(numberOfThreads);

        JButton button1 = new JButton("Submit SwingWorker 1");
        button1.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                String workerName = "Worker 1";
                appendMessage("Submited " + workerName);
                SwingWorker worker = new TestWorker(workerName);
                threadPool.submit(worker);
            }
        });

        JButton button2 = new JButton("Submit SwingWorker 2");
        button2.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                String workerName = "Worker 2";
                appendMessage("Submited " + workerName);
                SwingWorker worker = new TestWorker(workerName);
                threadPool.submit(worker);
            }
        });

        JButton button3 = new JButton("Submit SwingWorker 3");
        button3.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                String workerName = "Worker 3";
                appendMessage("Submited " + workerName);
                SwingWorker worker = new TestWorker(workerName);
                threadPool.submit(worker);
            }
        });

        JPanel buttonsPanel = new JPanel();
        buttonsPanel.add(button1);
        buttonsPanel.add(button2);
        buttonsPanel.add(button3);
        frame.add(buttonsPanel, BorderLayout.PAGE_END);

        _textArea = new JTextArea("Submit some workers:\n");
        _textArea.setEditable(false);
        frame.add(new JScrollPane(_textArea));

        frame.setSize(600, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }


    private class TestWorker extends SwingWorker
    {
        public TestWorker(String name)
        {
            _name = name;
        }

        @Override
        protected Object doInBackground() throws Exception
        {
            String message = "A " + _name + " has started!";
            appendMessage(message);
            doHardWork();
            return null;
        }

        @Override
        protected void done()
        {
            String message = "A " + _name + " has finished!";
            appendMessage(message);
        }

        private void doHardWork()
        {
            try
            {
                Thread.sleep(2000);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }

        private String  _name;
    }

    private static void appendMessage(String message)
    {
        _textArea.append(message + "\n");
        System.out.println(message);
    }

    private static JTextArea    _textArea;
}

看起来像这样:

例如,如果线程数为 2,您将了解如何提交大量工作线程,一次需要 2 个线程并执行它们。

【讨论】:

    【解决方案3】:

    请看一下 SwingWorker 的源代码。 您可以使用类似于 execute() 方法的方法

     public final void execute() {
        getWorkersExecutorService().execute(this);
    }
    

    此时您可以创建一个 ExecutorService 并管理池

     SwingWorker<Boolean, Void> test = new SwingWorker<Boolean, Void>() {
            private ExecutorService service =  new ThreadPoolExecutor(5, 10,
                    10L, TimeUnit.MINUTES,
                    new LinkedBlockingQueue<Runnable>(),
                    new ThreadFactory() {
                        AtomicInteger count= new AtomicInteger();
                        @Override
                        public Thread newThread(Runnable r) {
                            return new Thread("Pooled SwingWorker " + count.getAndAdd(1));
                        }
                    });
            @Override
            protected Boolean doInBackground() throws Exception {
                return true;
            }
    
            public void doIt() {
                service.execute(this);
            }
    
        };
    

    【讨论】:

      【解决方案4】:

      你想的那一刻:太明显了!

      ExecutorService executorService = Executors.newFixedThreadPool(20);
      
      for (int i = 0; i < 500; i++) {
      
              SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
                      @Override
                      protected Boolean doInBackground() throws Exception {
      
                              System.out.println("One SwingWorker just ran!");
                              return true;
                      }
      
      
                      protected void done() {
      
                              boolean status;
                              try {
      
                                      status = get();
      
                              } catch (InterruptedException e) {
                              // This is thrown if the thread's interrupted.
                              } catch (ExecutionException e) {
                              // This is thrown if we throw an exception
                              // from doInBackground.
                              }
                      }
      
              };
      
      
              executorService.submit(worker);
      }
      


      效果很好!

      【讨论】:

      • 一切正常,但是...... done() 方法只被所有提交的进程调用一次?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-31
      • 2020-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多