等待多个SwingWorkers

请考虑下面的代码片段:

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

这里是向applet添加一个标签,显示Worker线程的一些中间结果(使用publish / process方法)。 最后,标签将从applet的窗格中移除。 我的问题是,我怎么能创build几个标签,每个都有自己的工作线程,并在完成后删除它们?

提前致谢。

更新:

我希望这会澄清我的问题。 当所有工人完成任务时,我不希望标签被一次全部清除,而是在每个工人完成之后。

更新2:

下面的代码似乎正在做我所需要的。 请评论我是否做得正确。 我有一种感觉,有什么不对劲。 一个问题是,button右侧的标签保持可见,尽pipe它们被移除。 setVisible(false)似乎解决了这个问题。 那是这样做的吗?

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

我打算在所有的工作人员都完成任务的时候把所有的标签一并删除。

如上所述,在这种情况下, CountDownLatch可以很好地工作。 在下面的例子中,每个worker在完成时调用latch.countDown() ,并且一个Supervisor worker阻塞latch.await()直到完成所有任务。 出于演示目的, Supervisor更新标签。 显示在评论中的批发清除在技术上是可能的,但通常不具吸引力。 相反,考虑一个JListJTable

工人闩锁测试

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

你有的代码已经在一定程度上做到了这一点。 当点击button时,您需要实际将标签添加到内容窗格。 像这样的东西:

  JLabel label = new JLabel(); getContentPane().add(label); getContentPane().validate(); new Worker(label).execute(); 

在标签中放置一些文本可能是一个好主意,所以当它被添加到屏幕时,您可以真正看到它。

  JLabel label = new JLabel("Hello...I am here"); 

最后在doInBackground()方法中,您可以添加一些代码来更新某个任务正在运行的标签:

  for(int i = 0;i < 100; i++){ Thread.sleep(20); label.setText("Counting..." + i); } 

这样你实际上看到任务正在运行。 如果多次单击该button,则会看到多个标签,并且每个标签在任务完成后都会消失。