Java SwingWorker запускает runnables из doInBackground () и как уведомить поток отправки события - PullRequest
4 голосов
/ 24 ноября 2011

просто выучите SwingWorker и у меня есть вопрос
(у меня есть поиск ответа на этот вопрос, но я не обращаюсь конкретно к этой настройке)

Я создаю небольшой сервер, который будет иметь максимальное одновременное значение 2Только -3 соединения.
Я использую Jframe, который имеет внутренний класс SwingWorker

В SwingWorker doInBackground() у меня есть:

while(true) {
  Socket client_socket = listen_socket.accept();
  Connection con = new Connection(client_socket, "name");
  Future<Connection> future = es.submit(con , con ); 
  tasks.add(future);
 }

Connection является runnable и объявлен как подкласс в SwingWorker.

До того, как runnable завершит свою работу, запишите запись в SQL.
Как может этот исполняемый файл до его смерти отправлять хедс-ап к Jframe потоку отправки события.
иJframe проверит SQL для новой записи и отобразит его пользователю.

что лучше сделать:

1 - создайте интерфейс, с помощью которого все работоспособные могут отправлять сообщения на Jframeпоток рассылки событий.

2 - используйте SwingWorker вместо runnables для всех новых подключений и Done() вызывайте метод на сервере SwingWorker, который вызывает метод в Jframe с использованием EventQueue.invokeLater..

3 - или используйте PropertyChangeListener (как-то не уверен)

4 - Пусть у каждого запускаемого файла s ref = Jframe и EventQueue.invokeLater..

Ответы [ 3 ]

1 голос
/ 24 ноября 2011

Документы SwingWorker довольно четкие. Вы должны создать подкласс SwingWorker и выполнить длинную задачу в методе doInBackground(). Вы должны обновить пользовательский интерфейс в методе done().

Это действительно так просто.

Edit:
Чтобы было понятнее. Предполагая, что ваш Connection класс расширяет SwingWorker, он не нуждается в реализации Runnable, а вы не должны явно предоставить пул потоков для запуска рабочих. Просто введите содержимое метода run() в doInBackground().

Теперь ваш основной цикл выглядит примерно так:

while (true) {
  Socket client_socket = listen_socket.accept();
  Connection con = new Connection(client_socket, "name");
  con.execute();
}

Вы, похоже, отправляете на ExecutorService в своем основном цикле. Есть ли для этого особая причина (обратите внимание, что SwingWorker управляет собственным внутренним ThreadPoolExecutor для рабочих потоков). Это ограничение количества одновременных клиентов? Если так, то есть другие способы сделать это.

1 голос
/ 24 ноября 2011

Я попытался создать пример SwingWorker, который генерирует фоновые рабочие потоки, результаты которых публикуются через фиксированный пул ExecutorService и CompletionService.У меня все еще есть некоторые вопросы, касающиеся безопасности потоков: создание рабочих потоков внутри одного потока, а затем вызов get для их будущего внутри другого потока (фоновый поток SwingWorker).

например:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.swing.*;

@SuppressWarnings("serial")
public class TestSwingWorker extends JPanel {
   public static final int POOL_SIZE = 4;
   private JTextArea tArea = new JTextArea(10, 30);
   private JButton doItBtn;

   public TestSwingWorker() {
      doItBtn = new JButton(new AbstractAction("Do It!") {
         public void actionPerformed(ActionEvent ae) {
            swingWorkerRunning(true);
            MySwingWorker mySW = new MySwingWorker();
            mySW.execute();
            tArea.append("SwingWorker started\n");
         }
      });
      JPanel btnPanel = new JPanel();
      btnPanel.add(doItBtn);
      tArea.setEditable(false);
      tArea.setFocusable(false);

      setLayout(new BorderLayout());
      add(new JScrollPane(tArea), BorderLayout.CENTER);
      add(btnPanel, BorderLayout.SOUTH);
   }

   private class MySwingWorker extends SwingWorker<String, String> {
      @Override
      protected String doInBackground() throws Exception {
         ExecutorService execService = Executors.newFixedThreadPool(POOL_SIZE);
         final CompletionService<String> completionService = new ExecutorCompletionService<String>(
               execService);
         new Thread(new Runnable() {

            @Override
            public void run() {
               for (int i = 0; i < POOL_SIZE; i++) {
                  final int index = i;
                  completionService.submit(new Callable<String>() {
                     public String call() throws Exception {
                        Thread.sleep(2000 * index + 500);
                        return "Callable " + index + " complete";
                     }
                  });
                  try {
                     Thread.sleep(1000);
                  } catch (InterruptedException e) {
                  }
               }
            }
         }).start();

         for (int i = 0; i < POOL_SIZE; i++) {
            Future<String> f = completionService.take();
            publish(f.get());
         }

         return "Do in background done";
      }

      @Override
      protected void process(List<String> chunks) {
         for (String chunk : chunks) {
            tArea.append(chunk + "\n");
         }
      }

      @Override
      protected void done() {
         try {
            tArea.append(get() + "\n");
         } catch (InterruptedException e) {
            e.printStackTrace();
         } catch (ExecutionException e) {
            e.printStackTrace();
         } finally {
            swingWorkerRunning(false);
         }
      }
   }

   public void swingWorkerRunning(boolean running) {
      doItBtn.setEnabled(!running);
   }

   private static void createAndShowGui() {
      TestSwingWorker mainPanel = new TestSwingWorker();

      JFrame frame = new JFrame("TestSwingWorker");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

Исправления приветствуются!

1 голос
/ 24 ноября 2011

Я бы пошел на следующее: иметь потокобезопасную очередь блокировки или список в родительском потоке, который будет передан рабочим потокам.После выполнения задачи рабочий поток опубликует сообщение, содержащее идентификатор записи результата, в эту очередь блокировки.Родительский поток блокирует очередь, ожидая результатов от дочерних потоков.Всякий раз, когда в очереди есть элемент, родительский поток берет его и получает данные из БД и отображает их пользователю.

...