问题 Swingworker实例不同时运行


我的电脑有4个内核,我正在运行Java swing gui程序。当我运行我的应用程序时,它只使用两个内核和大约30%的CPU利用率。我有大量要处理的文件,并希望将它们分成两个线程,以便使用更多的cpu更快地完成此任务。

我有一个名为PrepareTask的SwingWorker类,它有一个带有两个int的构造函数:

class PrepareTask extends SwingWorker<Void, Void> {
  int start, end;
  PrepareTask (int start, int end) { ... }
  ...
    public Void doInBackground() {... }
    public void done() { ... }

我创建了两个这样的实例:

  PrepareTask prepareTask = new PrepareTask(0,numberOfFiles/2);
  prepareTask.execute();
  PrepareTask prepareTask2 = new PrepareTask(numberOfFiles/2, numberOfFiles);
  prepareTask2.execute();

两者都被启动(它出现),但是当它运行时,我可以看到(打印stmts)第一个准备必须在第二个开始之前完成(在里面打印stmts)。 CPU利用率与以前相同,约为30%。它们当然都从同一个源中获取数据,即DefaultTableModel。

关于如何做到这一点或我做错了什么的想法? 谢谢。


4383
2017-09-25 20:07


起源

请注意,如果大多数处理时间涉及文件访问,那么拥有多个线程并不一定会使它更快,因为磁盘将成为您的瓶颈。您是否可以进一步开发对这些文件执行的处理? - jfpoilpret


答案:


这是SwingWorker行为从一个Java 6更新更改为另一个Java 6更新的结果。在Java 6的旧SUN错误数据库中实际上存在关于它的错误报告。

发生的事情是SUN将原始的SwingWorker实现从使用N个线程改为使用1个具有无界队列的线程。因此,您不能再同时运行两个SwingWorkers。 (这也会产生一种可能发生死锁的情况:如果一个swingworker等待另一个等待第一个,则一个任务可能会因此而进入死锁。)

你可以做些什么来解决这个问题,使用ExecutorService并在其上发布FutureTasks。这些将提供99%的SwingWorker API(SwingWorker是FutureTask派生物),您所要做的就是正确设置Executor。


16
2017-09-25 20:50



我以前见过这个,但你总结得比大多数人好:+1 - Hovercraft Full Of Eels
这应该在Java SE 6u21中修复: oracle.com/technetwork/java/javase/bugfixes6u21-156339.html - keuleJ
这是Bug: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6925575 - keuleJ


也许Swing正在控制线程的调度?或者SwingWorker的线程池大小为1(SwingWorker javadoc中没有关于运行多个SwingWorker线程的描述,我猜多个线程可能会导致Swing中出现一些困难的并发问题)。

如果你想做的就是并行运行一些处理, 你可以通过扩展这个简单的方法解决这个问题 Java的 Thread 上课,实施 run,打电话 SwingUtilities.invokeLater() 在 最后用任何更改来更新GUI:

    class PrepareTask extends Thread
    {
      PrepareTask (int start, int end) { ... }
      public void run() { ... ; SwingUtilities.invokeLater(new Runnable() { public void run() { do any GUI updates here } )}

用以下内容启动线程:

    prepareTask.start();

或者您的数据模型中的某些东西是单线程的并阻塞第二个线程? 在这种情况下,您必须使用数据模型解决该问题。


0
2017-09-25 20:31