Java SwingWorker launches runnables from doInBackground () and how to notify event dispatch thread

just get to know SwingWorker and ask a question
(I have a search for the answer to this question, but not specifically for this setting)

I am creating a small server that will have a maximum number of simultaneous 2-3 connections.
Im using Jframe which have SwingWorker inner class

In SwingWorker doInBackground() , I have:

 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 is runnable and is declared as a subclass of SwingWorker .

Before runnable completes this, write an entry in SQL.
How can this happen when this happens before he dies, send heads-up on the Jframe stream.
and Jframe will check the SQL for the new record and display it to the user.

what is better to do:

1 - create an interface in which all runnable can send messages to the Jframe stream of the event stream.

2 - use the SwingWorker insted from runnables for all new connections and Done() call the method on the SwingWorker server, which calls the method in Jframe using EventQueue.invokeLater..

3 - or use PropertyChangeListener (somehow not sure)

4 - Let each runnables have s ref up to Jframe and do EventQueue.invokeLater..

+4
source share
3 answers

SwingWorker pretty SwingWorker . You must subclass SwingWorker and complete the long task in the doInBackground() method. You must update the interface in the done() method.

It's really that simple.

Edit:
To make it clearer. Assuming your Connection extends SwingWorker class doesnโ€™t need to implement Runnable , and you donโ€™t need to explicitly provide a thread pool for running workers. Just put the contents of the run() method in doInBackground() .

Now your main loop looks something like this:

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

It seems you are sending the ExecutorService to your main loop. Is there a specific reason for this (note that SwingWorker manages its own internal ThreadPoolExecutor for workflows). Limit the number of concurrent clients? If so, there are other ways to do this.

+1
source

I would go for the following: do you have a queue thread lock or a list in the parent thread that will be passed to worker threads. After completing the task, the worker thread will send a message containing the identifier of the result record to this lock queue. The parent thread will block the queue, waiting for results from child threads. Whenever an item is in the queue, the parent thread receives it and sends data from the database and displays it to the user.

+1
source

I tried to create a SwingWorker example that generates workflow threads whose results are published through the fixed pool ExecutorService and CompletionService. I still have some questions regarding thread safety for creating workflows inside one thread, and then a call to get their futures inside another thread (SwingWorker background thread).

eg:

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

Corrections are most welcome!

+1
source

Source: https://habr.com/ru/post/1382899/


All Articles