我做了一个swings应用程序但是有一个问题如下:
我从Event Dispatch Thread发起了一个名为“Thread-Main”的SwingWorker线程,并将GUI的JLabel引用传递给了“Thread-Main”。
现在我已经从“Thread-Main”开始了10个线程。
现在我希望所有10个线程都应该更新JLabel。
我该怎么做?
有人告诉我,我可以通过首先创建SwingWorker的所有10个线程子类然后调用publish(“”)方法并在该“publish”方法中传递字符串然后收集所有已发布的字符串来实现此目的。 “Thread-Main”中的以下方法
@Override
protected void process(List<String> labelStrings) {
String count = labelStrings.get(labelStrings.size() - 1);
label.setText(count); // label is a reference to a label in the GUI
}
答案 0 :(得分:4)
也许更简单的方法是在SwingUtilities.invokeLater(...)方法中包装更新GUI的代码。
编辑:在您想要更新标签的个别线程中:
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
label.setText(...);
}
});
答案 1 :(得分:3)
SwingWorker
代码,你会发现它在内部使用ThreadPoolExecutor
,最多包含10个线程。如果同时启动多个SwingWorker
,它们将全部使用此执行程序运行。但是,您无法直接控制后台线程是否并行执行。我推荐的解决方案是:
SwingWorker
。doInBackground()
方法中,直接或使用ExecutorService
启动10个主题。CountDownLatch
或CompletionService
在主线程(即SwingWorker
后台线程)和工作线程之间进行同步。示例强>
定义要调用的工作线程数,并声明要更新的JLabel。
final int nThreads = 10;
JLabel myLbl = new JLabel();
将我们希望执行的工作单元定义为Callable<String>
。 String
结果将用于更新JLabel
。
private static class MyCallable implements Callable<String> {
public String call() { ... }
}
现在开始SwingWorker
,这将启动多个并行工作人员进行任何处理。工作人员不会通过调用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.
}
}
答案 2 :(得分:0)
为什么你需要10个线程?为什么不会有一个额外的线程呢?
真正的问题:你要解决的问题是什么?
回答你的直接问题:
1)是的,这是正确的方法 2)是的,线程应该是SwingWorkers(如果你使用netbeans,你也可以使用Tasks,它们也是SwingWorker的子类)
3)如果你想从edt中获得一个单独的线程;然后你需要使用swingworker;所以方式就是这样做的。
祝你好运!