如何与Java中的两(2)个SwingWorker类共享数据
我有两个SwingWorker类: FileDivisionThread
和FileDivisionThread
我将执行这两个线程。 行计数结束后,会将结果传递给文件分割线程。
我不知道如何将结果传递给启动的线程。
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.Timer; import javax.swing.border.EmptyBorder; public class ExecutorAndSwingWorker2 { private JFrame frame = new JFrame(); private JButton button1; private JButton button2; private JButton button3; private JButton button4; private JPanel buttonPanel = new JPanel(); private Executor executor = Executors.newCachedThreadPool(); private javax.swing.Timer timer1; private javax.swing.Timer timer2; private javax.swing.Timer timer3; private javax.swing.Timer timer4; private Random random = new Random(); public ExecutorAndSwingWorker2() { button1 = new JButton(" Executor + SwingWorker Thread No.1 "); button1.setFocusable(false); button2 = new JButton(" Executor + SwingWorker Thread No.2 "); button3 = new JButton(" Executor + SwingWorker Thread No.3 "); button4 = new JButton(" Executor + SwingWorker Thread No.4 "); buttonPanel = new JPanel(); buttonPanel.setBorder(new EmptyBorder(15, 15, 15, 15)); buttonPanel.setLayout(new GridLayout(2, 2, 20, 20)); buttonPanel.add(button1); buttonPanel.add(button2); buttonPanel.add(button3); buttonPanel.add(button4); frame.setTitle("Shaking Button Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(buttonPanel); frame.setPreferredSize(new Dimension(700, 170)); frame.setLocation(150, 100); frame.pack(); frame.setVisible(true); executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton1")); // non on EDT } private void startButton1() { System.out.println("Starting long Thread == startButton1()"); try { Thread.sleep(15000); } catch (InterruptedException ex) { } } private void startButton2() { System.out.println("Starting long Thread == startButton2()"); try { Thread.sleep(17500); } catch (InterruptedException ex) { } } private void startButton3() { System.out.println("Starting long Thread == startButton3()"); try { Thread.sleep(12500); } catch (InterruptedException ex) { } } private void startButton4() { System.out.println("Starting long Thread == startButton4()"); try { Thread.sleep(20000); } catch (InterruptedException ex) { } } private void colorAction1() { timer1 = new Timer(1000, new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { random = new Random(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { button1.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128))); button1.validate(); button1.repaint(); } }); } }); timer1.setDelay(500); timer1.setRepeats(true); timer1.start(); } private void colorAction2() { timer2 = new Timer(1200, new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { random = new Random(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { button2.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128))); button2.validate(); button2.repaint(); } }); } }); timer2.setDelay(500); timer2.setRepeats(true); timer2.start(); } private void colorAction3() { timer3 = new Timer(1400, new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { random = new Random(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { button3.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128))); button3.validate(); button3.repaint(); } }); } }); timer3.setDelay(500); timer3.setRepeats(true); timer3.start(); } private void colorAction4() { timer4 = new Timer(1600, new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { random = new Random(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { button4.setBackground(new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128))); button4.validate(); button4.repaint(); } }); } }); timer4.setDelay(500); timer4.setRepeats(true); timer4.start(); } private void endButton1() { timer1.stop(); button1.setBackground(null); System.out.println("Long Thread Ends == startButton1()"); executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton3")); // non on EDT } private void endButton2() { timer2.stop(); button2.setBackground(null); System.out.println("Long Thread Ends == startButton2()"); } private void endButton3() { timer3.stop(); button3.setBackground(null); System.out.println("Long Thread Ends == startButton3()"); executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton2")); // non on EDT executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton4")); // non on EDT } private void endButton4() { timer4.stop(); button4.setBackground(null); System.out.println("Long Thread Ends == startButton4()"); executor.execute(new ExecutorAndSwingWorker2.MyTask("startButton1")); // non on EDT } private class MyTask extends SwingWorker<Void, Integer> { private String str; private String namePr; private JDialog dialog = new JDialog(); MyTask(String str) { this.str = str; addPropertyChangeListener(new SwingWorkerCompletionWaiter(dialog, str, namePr)); } @Override protected Void doInBackground() throws Exception { if (str.equals("startButton1")) { colorAction1(); startButton1(); } else if (str.equals("startButton2")) { colorAction2(); startButton2(); } else if (str.equals("startButton3")) { colorAction3(); startButton3(); } else if (str.equals("startButton4")) { colorAction4(); startButton4(); } return null; } @Override protected void process(List<Integer> progress) { System.out.println(str + " " + progress.get(progress.size() - 1)); } @Override protected void done() { if (str.equals("startButton1")) { endButton1(); } else if (str.equals("startButton2")) { endButton2(); } else if (str.equals("startButton3")) { endButton3(); } else if (str.equals("startButton4")) { endButton4(); } } } private class SwingWorkerCompletionWaiter implements PropertyChangeListener { private JDialog dialog; private String str; private String namePr; SwingWorkerCompletionWaiter(JDialog dialog, String str, String namePr) { this.dialog = dialog; this.str = str; this.namePr = namePr; } @Override public void propertyChange(PropertyChangeEvent event) { if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) { System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else { System.out.println("Thread Status with Name :" + str + ", Something wrong happends "); } } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { ExecutorAndSwingWorker2 executorAndSwingWorker = new ExecutorAndSwingWorker2(); } }); } }
SwingWorker.execute()
是越野车 ,将只能连续执行任务。 使用ExecutorService.execute()
进行并发:
import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RunnableFuture; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.WindowConstants; public class MyFrame extends JFrame implements ActionListener { /** * Test Driver */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { MyFrame frame = new MyFrame("Swing Concurrency Test"); frame.setVisible(true); } }); } /** * Thread Executor * (must be explicitly shutdown, see WindowAdapter below) */ private final ExecutorService exec = Executors.newFixedThreadPool(2); /** * Button action */ @Override public void actionPerformed(ActionEvent e) { button.setEnabled(false); textArea.append("\nStarting both tasks...\n"); // start both tasks, pass a reference to outer task FileLineCounterThread counterTask = new FileLineCounterThread(); exec.execute(counterTask); FileDivisionThread divisionTask = new FileDivisionThread(counterTask); exec.execute(divisionTask); } /** * Counter task */ private class FileLineCounterThread extends SwingWorker<Long, String> { private String template = "[FileLineCounterThread] %s\n"; @Override protected Long doInBackground() throws Exception { // do some work publish("started..."); Thread.sleep(10000); // return the result return 42L; } @Override protected void process(List<String> chunks) { for (String chunk : chunks) { textArea.append(String.format(template, chunk)); } } @Override protected void done() { try { textArea.append(String.format( template, "complete. Counted: " + get())); } catch (Exception e) { // catch any exceptions thrown during execution e.printStackTrace(); } } } /** * File Division task */ private class FileDivisionThread extends SwingWorker<String, String> { private RunnableFuture<Long> counterTask; private String template = " [FileDivisionThread] %s\n"; public FileDivisionThread(RunnableFuture<Long> counterTask) { this.counterTask = counterTask; } @Override protected String doInBackground() throws Exception { // do some initial work publish("started..."); Thread.sleep(2000); // wait for other task to complete and get result publish("Waiting for line counter to finish..."); long numLines = counterTask.get(); publish("Line count received: " + numLines); // do the rest of the work and return result Thread.sleep(5000); return "complete."; } @Override protected void process(List<String> chunks) { for (String chunk : chunks) { textArea.append(String.format(template, chunk)); } } @Override protected void done() { try { textArea.append(String.format(template, get())); button.setEnabled(true); } catch (Exception e) { // catch any exceptions thrown during execution e.printStackTrace(); } } } ///////////////////////// //// GUI Boilerplate //// ///////////////////////// private JScrollPane scroller = new JScrollPane(); private JTextArea textArea = new JTextArea(); private JButton button = new JButton("Start"); public MyFrame(String windowTitle) { super(windowTitle); initComponents(); } private void initComponents() { addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { exec.shutdownNow(); System.exit(0); } }); button = new JButton("Start"); button.addActionListener(this); textArea = new JTextArea(); textArea.setColumns(35); textArea.setRows(15); scroller.setViewportView(textArea); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); getContentPane().setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(10, 0, 0, 0); getContentPane().add(button, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(10, 10, 10, 10); getContentPane().add(scroller, gridBagConstraints); pack(); } }
用于字符数据的PipedReader / Writer和用于二进制数据的PipedInput / OutputStream
在java.io.
问候,Stéphane
永远不要动手,永远不要放弃Executor和SwingWorker
1 / 执行者和SwingWorker错误
2 /保持并检查由Executor和活SwingWorkers线程启动的线程数目,以避免捕获上述错误
3 /检查Executor的最大数量或者最后的munber
编辑由OP的要求改变
import java.beans.*; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import javax.swing.JDialog; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; public class ExecutorAndSwingWorker1 { private static Executor executor = Executors.newCachedThreadPool(); private static void startButton1() { System.out.println("Starting long Tread == startButton1()"); try { Thread.sleep(1000); } catch (InterruptedException ex) { } } private static void startButton2() { System.out.println("Starting long Tread == startButton2()"); try { Thread.sleep(3000); } catch (InterruptedException ex) { } } private static void startButton3() { System.out.println("Starting long Tread == startButton3()"); try { Thread.sleep(1500); } catch (InterruptedException ex) { } } private static void startButton4() { System.out.println("Starting long Tread == startButton4()"); try { Thread.sleep(500); } catch (InterruptedException ex) { } } private static void endButton1() { System.out.println("Long Tread Ends == startButton1()"); executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton3")); // non on EDT } private static void endButton2() { System.out.println("Long Tread Ends == startButton2()"); executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton4")); // non on EDT } private static void endButton3() { System.out.println("Long Tread Ends == startButton3()"); } private static void endButton4() { System.out.println("Long Tread Ends == startButton3()"); } private static class MyTask extends SwingWorker<Void, Integer> { private String str; private String namePr; private JDialog dialog = new JDialog(); MyTask(String str) { this.str = str; addPropertyChangeListener(new SwingWorkerCompletionWaiter(dialog, str, namePr)); } @Override protected Void doInBackground() throws Exception { if (str.equals("startButton1")) { startButton1(); } else if (str.equals("startButton2")) { startButton2(); } else if (str.equals("startButton3")) { startButton3(); } else if (str.equals("startButton4")) { startButton4(); } return null; } @Override protected void process(List<Integer> progress) { System.out.println(str + " " + progress.get(progress.size() - 1)); } @Override protected void done() { if (str.equals("startButton1")) { endButton1(); } else if (str.equals("startButton2")) { endButton2(); } else if (str.equals("startButton3")) { endButton3(); } else if (str.equals("startButton4")) { endButton4(); } } } private static class SwingWorkerCompletionWaiter implements PropertyChangeListener { private JDialog dialog; private String str; private String namePr; SwingWorkerCompletionWaiter(JDialog dialog, String str, String namePr) { this.dialog = dialog; this.str = str; this.namePr = namePr; } @Override public void propertyChange(PropertyChangeEvent event) { if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) { System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue()); } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) { System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue()); } else { System.out.println("Thread Status with Name :" + str + ", Something wrong happends "); } } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton1")); // non on EDT executor.execute(new ExecutorAndSwingWorker1.MyTask("startButton2")); // non on EDT } }); } private ExecutorAndSwingWorker1() { } }
我不确定这是一个您应该使用的解决scheme,它会破坏您使用SwingWorker的简单性和安全性,但是为了完整性,我会提及它。
放两个线程可以看到他们的字段:一个布尔值,称为hasValue
,初始化为false,一个int(或long)称为countValue
。 两者都必须声明为volatile
。 当计数器线程完成时,将计数放在countValue
。 然后将hasValue
设置为true。 除法线程可以定期检查`hasValue',并在计数可用时进行计数。
如果这个部门提供的价值一旦得到计数就会更加准确,这是可以的。 更可能的是,它正在做一些工作,然后等待计数。 在这种情况下,设置第三个字段叫countMonitor
,定义为final Object
。 当它完成初始工作时,检查hasValue
。 如果这是真的,那么抓住这个值并继续。 如果为false,则调用countMonitor
的wait
方法,并在通知时继续。 计数器线程完成后,应将值放入hasValue
和countValue
后 ,始终调用countMonitor
的notifyAll
方法。
我在这里漏了一点。 Object
的javadoc会告诉你需要的同步和检查exception。 你的devise非常简单,你不会为multithreading产生的通常的超自然恐怖故事感到困扰。 我希望。 但是如果你走这条路,你可能想做一些研究。 (如果你在同一个环节重复整个过程,你肯定会想做很多的研究。)