Вопрос

Я создал приложение swings, но в нем есть одна проблема, которая заключается в следующем:

Я инициировал поток SwingWorker с именем "Thread-Main" из потока отправки событий и передал ссылку JLabel графического интерфейса на "Thread-Main".

Теперь я запустил 10 потоков из "Thread-Main".

Теперь я хочу, чтобы все 10 потоков обновили JLabel.

Как я могу это сделать?

Кто-то сказал мне, что я могу сделать это, сначала создав все подклассы 10 потоков SwingWorker, а затем вызвав метод 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. Есть ли какой-нибудь другой способ сделать это?
Это было полезно?

Решение

  1. НЕТ - Это неправильный подход если вы хотите контролировать количество потоков себя.Почему?Потому что, если вы посмотрите на SwingWorker кода вы увидите, что он использует ThreadPoolExecutor внутренне содержащий максимум 10 потоков.Если вы начнете использовать ряд SwingWorkerодновременно все они будут запускаться с использованием этого исполнителя.Однако, у вас нет прямого контроля над тем, выполняются ли фоновые потоки параллельно.
  2. См. пункт 1.
  3. Моим рекомендуемым решением было бы:

    • Создайте единый SwingWorker.
    • В пределах doInBackground() метод запускает 10 потоков либо напрямую, либо с помощью ExecutorService.
    • Используйте 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.
  }
}

Другие советы

Возможно, более простой подход - обернуть код, который обновляет графический интерфейс, в метод SwingUtilities.invokeLater (...).

Редактировать: в ваших отдельных темах, когда вы хотите обновить ярлык, который вы делаете:

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

зачем тебе 10 потоков? почему не один дополнительный поток не делает?

реальный вопрос: какую проблему вы пытаетесь решить?

чтобы ответить на ваши прямые вопросы:

1) да, это правильный подход 2) да, потоки должны быть SwingWorkers (если вы используете netbeans, вы также можете использовать Задачи, которые также являются подклассами SwingWorker)

3) если вы хотите иметь отдельный поток от edt; тогда вам нужно использовать качельщика; так что это способ сделать это.

удачи!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top