Java – wait for multiple swingworkers
Consider the following code snippet:
import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.InvocationTargetException; import javax.swing.*; public class TestApplet extends JApplet { @Override public void init() { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { createGUI(); } }); } catch(InterruptedException | InvocationTargetException ex) { } } private void createGUI() { getContentPane().setLayout(new FlowLayout()); JButton startButton = new JButton("Do work"); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { JLabel label = new JLabel(); new Worker(label).execute(); } }); getContentPane().add(startButton); } private class Worker extends SwingWorker<Void,Void> { JLabel label; public Worker(JLabel label) { this.label = label; } @Override protected Void doInBackground() throws Exception { // do work return null; } @Override protected void done() { getContentPane().remove(label); getContentPane().revalidate(); } } }
This is to add a tag to the applet to display some intermediate results of the worker thread (using the publish / process method) Finally, the tag is removed from the pane of the applet My question is, how do I create several tags, each with its own worker thread, and delete them when I finish?
Thank you in advance
to update:
I hope this will clarify my question When all the staff have finished the task, instead of deleting all the tags immediately after each staff has finished
Update 2:
The following code seems to be doing what I need Please comment on whether I have done the right way I have a feeling that there is something wrong One problem is that after removing the delete button, the label on the right side of the button is still visible Setvisible (false) seems to solve this problem Is that it?
import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.InvocationTargetException; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.*; public class TestApplet extends JApplet { private Queue<JLabel> labels = new LinkedList<>(); private static final Random rand = new Random(); @Override public void init() { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { createGUI(); } }); } catch(InterruptedException | InvocationTargetException ex){} } private void createGUI() { getContentPane().setLayout(new FlowLayout()); JButton startButton = new JButton("Do work"); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { ExecutorService executor = Executors.newFixedThreadPool(10); for(int i = 0; i < 10; i++) { JLabel label = new JLabel(); getContentPane().add(label); executor.execute(new Counter(label)); } } }); getContentPane().add(startButton); } private class Counter extends SwingWorker<Void,Integer> { private JLabel label; public Counter(JLabel label) { this.label = label; } @Override protected Void doInBackground() throws Exception { for(int i = 1; i <= 100; i++) { publish(i); Thread.sleep(rand.nextInt(80)); } return null; } @Override protected void process(List<Integer> values) { label.setText(values.get(values.size() - 1).toString()); } @Override protected void done() { labels.add(label); if(labels.size() == 10) { while(!labels.isEmpty()) getContentPane().remove(labels.poll()); getContentPane().revalidate(); } } } }
Solution
As described here, countdownlatch works well in this context In the following example, each worker calls latch. When finished Countdown(), and the supervisor worker blocks latch Await() until all tasks are completed For demonstration purposes, the supervisor updates the label Critical deletion, as shown in the comments, is technically possible but usually unattractive Instead, consider a JList or JTable
import java.awt.Color; import java.awt.EventQueue; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.*; /** * @see https://stackoverflow.com/a/11372932/230513 * @see https://stackoverflow.com/a/3588523/230513 */ public class WorkerLatchTest extends JApplet { private static final int N = 8; private static final Random rand = new Random(); private Queue<JLabel> labels = new LinkedList<JLabel>(); private JPanel panel = new JPanel(new GridLayout(0,1)); private JButton startButton = new JButton(new StartAction("Do work")); public static void main(String[] args) { EventQueue.invokelater(new Runnable() { @Override public void run() { JFrame frame = new JFrame(); frame.setTitle("Test"); frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE); frame.add(new WorkerLatchtest().createGUI()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } @Override public void init() { EventQueue.invokelater(new Runnable() { @Override public void run() { add(new WorkerLatchtest().createGUI()); } }); } private JPanel createGUI() { for (int i = 0; i < N; i++) { JLabel label = new JLabel("0",JLabel.CENTER); label.setOpaque(true); panel.add(label); labels.add(label); } panel.add(startButton); return panel; } private class StartAction extends AbstractAction { private StartAction(String name) { super(name); } @Override public void actionPerformed(ActionEvent e) { startButton.setEnabled(false); CountDownLatch latch = new CountDownLatch(N); ExecutorService executor = Executors.newFixedThreadPool(N); for (JLabel label : labels) { label.setBackground(Color.white); executor.execute(new Counter(label,latch)); } new Supervisor(latch).execute(); } } private class Supervisor extends SwingWorker<Void,Void> { CountDownLatch latch; public Supervisor(CountDownLatch latch) { this.latch = latch; } @Override protected Void doInBackground() throws Exception { latch.await(); return null; } @Override protected void done() { for (JLabel label : labels) { label.setText("Fin!"); label.setBackground(Color.lightGray); } startButton.setEnabled(true); //panel.removeAll(); panel.revalidate(); panel.repaint(); } } private static class Counter extends SwingWorker<Void,Integer> { private JLabel label; CountDownLatch latch; public Counter(JLabel label,CountDownLatch latch) { this.label = label; this.latch = latch; } @Override protected Void doInBackground() throws Exception { int latency = rand.nextInt(42) + 10; for (int i = 1; i <= 100; i++) { publish(i); Thread.sleep(latency); } return null; } @Override protected void process(List<Integer> values) { label.setText(values.get(values.size() - 1).toString()); } @Override protected void done() { label.setBackground(Color.green); latch.countDown(); } } }