javax.swing.SwingWorker 中的问题

发布于 2024-08-09 03:13:17 字数 681 浏览 8 评论 0原文

我已经制作了一个 swings 应用程序,但有一个问题如下:

我从事件调度线程启动了一个名为“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 
}
  1. 上面的做法是否正确呢?
  2. 这 10 个线程应该是 SwingWorker 的子类吗?
  3. 还有其他方法可以做到这一点吗?

I have made a swings application but there is one problem in that which is as follow:

I have initiated a SwingWorker thread named "Thread-Main" from the Event Dispatch Thread and have passed a JLabel reference of the GUI to the "Thread-Main".

Now I have started 10 threads from the "Thread-Main".

Now I want that all the 10 threads should update the JLabel.

How can I do that?

Someone told me that I can do this by first making all the 10 threads subclasses of SwingWorker and then calling the publish("") method and passing the string in that "publish" method and then collecting all the published strings by the following method in "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 
}
  1. Is the above approach is correct to do that?
  2. Should the 10 threads be subclasses of SwingWorker?
  3. Is there any other way to do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

失去的东西太少 2024-08-16 03:13:17

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

编辑:在您的个人线程中,每当您想要更新标签时,您都会执行以下操作:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        label.setText(...);
    }
});

Maybe an easier approach is to wrap the code that updates the GUI in a SwingUtilities.invokeLater(...) method.

Edit: In your individual threads whenever you want to update the label you do:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        label.setText(...);
    }
});
清音悠歌 2024-08-16 03:13:17
  1. - 如果您想自己控制线程数,那么这是不正确的方法。为什么?因为如果您查看 SwingWorker 代码,您会发现它使用内部最多包含 10 个线程的 ThreadPoolExecutor。如果您同时启动多个 SwingWorker,它们都将使用此执行器运行。但是,您无法直接控制后台线程是否并行执行
  2. 请参阅第 1 点。
  3. 我推荐的解决方案是:

    • 创建一个 SwingWorker
    • doInBackground() 方法中直接或通过使用 ExecutorService 启动 10 个线程。
    • 使用 CountDownLatchCompletionService 在主线程(即 SwingWorker 后台线程)和工作线程之间进行同步。

示例

定义要调用的工作线程数并声明要更新的 JLabel。

final int nThreads = 10;
JLabel myLbl = new JLabel();

将我们希望执行的工作单元定义为 CallableString 结果将用于更新JLabel

private static class MyCallable implements Callable<String> {
  public String call() { ... }
}

现在启动一个 SwingWorker,它将依次启动多个并行工作线程来执行任何处理。工作线程不会通过调用 done() 返回结果(因此是 Void 类型),但编组中间String< /code> 通过调用 process(String... chunks) 将结果返回到 Swing 线程。

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.
  }
}
  1. No - This is the incorrect approach if you want to control the number of threads yourself. Why? Because if you look at the SwingWorker code you'll see that it uses a ThreadPoolExecutor internally containing a maximum of 10 threads. If you kick off a number of SwingWorker's concurrently they will all run using this executor. However, you have no direct control over whether the background threads are executed in parallel.
  2. See point 1.
  3. My recommended solution would be:

    • Create a single SwingWorker.
    • Within the doInBackground() method kick off 10 threads either directly or by using an ExecutorService.
    • Use a CountDownLatch or CompletionService to synchronize between your master thread (i.e. SwingWorker background thread) and worker threads.

Example

Define the number of worker threads to invoke and declare the JLabel to be updated.

final int nThreads = 10;
JLabel myLbl = new JLabel();

Define the unit of work we wish to execute as a Callable<String>. The String result will be used to update the JLabel.

private static class MyCallable implements Callable<String> {
  public String call() { ... }
}

Now kick off a SwingWorker, which will in turn kick off multiple parallel workers to do any processing. The worker will not return a result via the call to done() (hence the Void type) but will marshall intermediate String results back onto the Swing thread by calling process(String... chunks).

new SwingWorker<Void, String>() {
  // See method definitions below.
}.execute();

Define doInBackground() to kick off the worker threads and block for each result using a 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);
  }
}

Now we implement process(String... chunks) to simply update the JLabel when called.

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]);
  }
}

Finally we override done() to marshall any exceptions back onto the Swing thread.

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.
  }
}
心意如水 2024-08-16 03:13:17

为什么需要10个线程?为什么不用一根额外的线程呢?

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

回答您的直接问题:

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

3) 如果您想拥有与 edt 分开的线程;那么你需要使用摇摆工人;这就是做到这一点的方式

祝你好运!

why do you need 10 threads? why won't one extra thread do?

the real question: what is the problem you are trying to solve?

to answer your direct questions:

1) yes, that is the correct approach
2) yes, the threads should be SwingWorkers (if you are using netbeans, you can also use Tasks, which are subclasses of SwingWorker as well)

3) if you want to have a separate thread from the edt; then you need to use a swingworker; so that is the way to do it.

good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文