0

我做了一个swings应用程序,但是有一个问题如下:

我从 Event Dispatch Thread 启动了一个名为“Thread-Main”的 SwingWorker 线程,并将 GUI 的 JLabel 引用传递给了“Thread-Main”。

现在我已经从“Thread-Main”启动了 10 个线程。

现在我希望所有 10 个线程都应该更新 JLabel。

我怎样才能做到这一点?

有人告诉我,我可以通过首先将所有 10 个线程创建为 SwingWorker 的子类,然后调用 publish("") 方法并将字符串传递给该“发布”方法,然后通过以下方法收集所有已发布的字符串“线程主”

@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 
}
  1. 上述方法是否正确?
  2. 这 10 个线程应该是 SwingWorker 的子类吗?
  3. 有没有其他方法可以做到这一点?
4

3 回答 3

4

也许更简单的方法是将更新 GUI 的代码包装在 SwingUtilities.invokeLater(...) 方法中。

编辑:只要您想更新您所做的标签,就在您的个人线程中:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        label.setText(...);
    }
});
于 2009-10-26T14:25:44.673 回答
3
  1. 否-如果您想自己控制线程数,这是不正确的方法。为什么?因为如果您查看SwingWorker代码,您会发现它在ThreadPoolExecutor内部使用了最多包含 10 个线程的线程。如果您同时启动多个SwingWorker',它们都将使用此执行程序运行。但是,您无法直接控制后台线程是否并行执行
  2. 见第 1 点。
  3. 我推荐的解决方案是:

    • 创建单个SwingWorker.
    • 在该doInBackground()方法中直接启动 10 个线程或使用ExecutorService.
    • 使用CountDownLatchorCompletionService在主线程(即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.
  }
}
于 2009-10-26T14:50:46.667 回答
0

为什么需要 10 个线程?为什么没有一个额外的线程呢?

真正的问题:您要解决的问题是什么?

回答您的直接问题:

1) 是的,这是正确的做法 2) 是的,线程应该是 SwingWorkers(如果你使用的是 netbeans,你也可以使用 Tasks,它也是 SwingWorker 的子类)

3)如果你想从 edt 有一个单独的线程;那么你需要使用swingworker;所以这就是这样做的方法。

祝你好运!

于 2009-10-26T14:25:37.297 回答