Java SwingWorker和多线程

8
我正在设计一个Java GUI驱动的应用程序,它运行许多独立的任务,每个任务都在其自己的SwingWorker扩展类中执行。这是我通常使用的正常设计,以便在其自己的线程上运行任务,并仍然保持EDT空闲以更新GUI。每个SwingWorker都使用Executors.newCachedThreadPool在其自己的线程上启动。
然而,在一个特定的类中,有一个需要相当长时间处理的任务。该任务包含一个for循环,最多执行六次的某些计算。
我想到了在各自的线程中实现这六个计算中的每一个,以加快处理时间,但我不确定实现此目的的最佳方法。
是否可以同时扩展SwingWorker并实现Runnable,然后在for循环中使用void Run()方法,每次启动一个新线程,或使用cachedThreadPool。
还是最好只使用标准的Thread()实现?
欢迎提供任何建议或建议。
谢谢!

8
我考虑将六个计算过程分别实现在各自的线程中以加快处理速度。但是,这种用并行计算来加速CPU密集型应用程序的方法只有在你运行应用程序的CPU至少有6个核心可用于Java应用程序时才能提高速度。如果你只有两个核心,那么生成6个线程而不是两个线程实际上会使你的程序变慢。 - TacticalCoder
啊,是的,那很有道理!谢谢。 - Joshua Craven
@user988052,那没有任何意义。如果您有x个线程,则不一定需要至少x个核心才能使程序运行更快。只要JVM有多于1个逻辑CPU可用,操作系统就会尝试将这些线程分配到这些逻辑CPU中。更多的逻辑CPU-->>每个CPU的线程更少-->>完成得更快。当涉及到一些锁时,它可能会更加复杂,但通常是这样工作的。 - Radu Murzea
@SoboLAN:这确实很有道理:如果你的应用程序受到CPU限制,那么通过生成更多线程来提供更多的CPU周期并不能神奇地使其可用!这是行不通的。顺便说一下,相当多的人点赞了我的评论;) - TacticalCoder
1个回答

8

user988052说得没错 - 如果你没有多核CPU,将计算分配到六个不同的线程中会因为创建和管理线程的开销而减慢应用程序的速度。

如果你仍然想要在六个单独的线程中进行这些计算,你可以使用SwingWorker作为管理线程,并在其中生成5-6个新线程。使用ExecutorService是正确的方式,因为它使用线程池,从而最小化了创建和处理线程所需的开销。

编辑:回答你的评论:

我认为最好的方法是将你的计算实现为一个Runnable(以便每个六个计算可以单独运行),然后简单地使用ExecutorService,实例化六次你的Runnable并使用ExecutorService.submit(Runnable task)。你可以在SwingWorker.doInBackground()方法中完成所有这些操作。

你永远不应该自己调用run()方法 - 让Thread/ExecutorService来做。


那我需要在SwingWorker类中创建一个run方法,然后每次想要使用Executor执行新线程时调用run方法吗? - Joshua Craven
1
我认为这很大程度上取决于你期望计算所需的时间。如果我们谈论的是大约2秒的计算时间,那么使用6个线程可能不是一个好主意。但如果超过了这个时间(10秒、30秒、1分钟、5分钟等),那么使用6个线程是有意义的。在当今计算机中,创建/管理/切换这6个线程所产生的开销非常低廉,不应该成为问题。如果你认为创建这6个线程更合理,请这样做。如果用户拥有双核/三核/四核等CPU,甚至可能加快速度。 - Radu Murzea
@SoboLAN:这就是为什么我说“如果你仍然想要在六个独立的线程中进行这些计算”。如果创建六个线程可以提高代码的可读性/可维护性,那就去做吧。否则,这只是额外的开销(即使很小),并没有带来任何好处。 - mort
谢谢Mort,我觉得这正是我需要阅读的。关于任务,循环中的五个运行需要1-20秒钟。然而第六个可能需要长达三个小时才能完成,并且它可能是最先开始的任务。我只想让那个任务自己完成,而不会拖延其他更短的任务。感谢所有的评论!!! - Joshua Craven
很好的答案,父Swing Worker需要等待执行器服务中的所有任务完成吗?换句话说,如果Swing Worker生成了这6个子任务并通过done方法完成执行,那么子任务是否会继续工作,还是它们将与原始Swing Worker线程一起被清理? - 219CID

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接