Проблема в javax.swing.SwingWorker - PullRequest
0 голосов
/ 26 октября 2009

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

Я инициировал поток 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. Есть ли другой способ сделать это?

Ответы [ 3 ]

4 голосов
/ 26 октября 2009

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

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

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        label.setText(...);
    }
});
3 голосов
/ 26 октября 2009
  1. Нет - это неправильный подход , если вы хотите самостоятельно контролировать количество потоков . Зачем? Потому что, если вы посмотрите на код SwingWorker, вы увидите, что он использует ThreadPoolExecutor внутри, содержащий максимум 10 потоков. Если вы одновременно запускаете несколько SwingWorker, все они будут работать с использованием этого исполнителя. Однако у вас нет прямого контроля над тем, выполняются ли фоновые потоки параллельно .
  2. См. Пункт 1.
  3. Мое рекомендуемое решение будет:

    • Создать сингл SwingWorker.
    • В методе doInBackground() запускается 10 потоков либо напрямую, либо с помощью ExecutorService.
    • Используйте CountDownLatch или CompletionService для синхронизации между вашим основным потоком (т.е. SwingWorker фоновым потоком) и рабочими потоками.
* +1033 * Пример * ** +1036 тысяча тридцать пять * Определите количество рабочих потоков для вызова и объявите 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. } }
0 голосов
/ 26 октября 2009

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

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

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

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

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

удачи!

...