- 否-如果您想自己控制线程数,这是不正确的方法。为什么?因为如果您查看
SwingWorker
代码,您会发现它在ThreadPoolExecutor
内部使用了最多包含 10 个线程的线程。如果您同时启动多个SwingWorker
',它们都将使用此执行程序运行。但是,您无法直接控制后台线程是否并行执行。
- 见第 1 点。
我推荐的解决方案是:
- 创建单个
SwingWorker
.
- 在该
doInBackground()
方法中直接启动 10 个线程或使用ExecutorService
.
- 使用
CountDownLatch
orCompletionService
在主线程(即SwingWorker
后台线程)和工作线程之间进行同步。
例子
定义要调用的工作线程数并声明要更新的 JLabel。
final int nThreads = 10;
JLabel myLbl = new JLabel();
将我们希望执行的工作单元定义为Callable<String>
. 结果String
将用于更新JLabel
.
private static class MyCallable implements Callable<String> {
public String call() { ... }
}
现在启动 a SwingWorker
,这将反过来启动多个并行工作人员进行任何处理。worker 不会通过调用返回结果done()
(因此是Void
类型),但会通过调用将中间结果编组String
回 Swing 线程process(String... chunks)
。
new SwingWorker<Void, String>() {
// See method definitions below.
}.execute();
定义doInBackground()
以启动工作线程并使用CompletionService
.
public Void doInBackground() throws Exception {
// Define executor service containing exactly nThreads threads.
ExecutorService execService = Executors.newFixedThreadPool(nThreads);
// Define completion service that will contain the processing results.
CompletionService compService = new ExecutorCompletionService(execService);
// Submit work to thread pool using the CompletionService. Future<String>
// instances will be added to the completion service's internal queue until complete.
for (int i=0; i<nThreads; ++i) {
compService.submit(new MyCallable());
}
// Take results from each worker as they appear and publish back to Swing thread.
String result;
while ((result = compService.take().get()) != null) {
publish(result);
}
}
现在我们实现process(String... chunks)
简单地更新JLabel
调用的时间。
public void process(String... chunks) {
if (chunks.length > 0) {
// Update label with last value in chunks in case multiple results arrive together.
myLbl.setText(chunks[chunks.length - 1]);
}
}
最后,我们重写done()
以将任何异常编组回 Swing 线程。
public void done() {
try {
get(); // Will return null (as per Void type) but will also propagate exceptions.
} catch(Exception ex) {
JOptionPane.show ... // Show error in dialog.
}
}