Cómo compartir datos con dos (2) clases SwingWorker en Java

Tengo dos clases FileLineCounterThread : FileLineCounterThread y FileDivisionThread

Ejecutaré los dos hilos. Cuando termina el hilo de recuento de líneas, pasará el resultado al subproceso de la División de archivos.

No tengo una idea sobre cómo pasar el resultado al hilo iniciado.

 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 { 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 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() tiene errores y solo ejecutará las tareas en serie. Use ExecutorService.execute() para concurrencia:

 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 { 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 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 { private RunnableFuture counterTask; private String template = " [FileDivisionThread] %s\n"; public FileDivisionThread(RunnableFuture 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 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 para datos de caracteres & PipedInput / OutputStream para datos binarios

en java.io.

Saludos, Stéphane

nunca se entrega, nunca se rinda con Executor y SwingWorker

1 / error para Ejecutor y SwingWorker

2 / mantener y verificar el número de subprocesos iniciados por Executor y los hilos de SwingWorkers activos con intenciones de evitar el error mencionado anteriormente

3 / verificar los números máximos para el ejecutor o restituirlos a munber final

EDIT modificado por los requisitos de 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 { 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 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() { } } 

No estoy seguro de que esta sea una solución que deba usar, y socava la simplicidad y la seguridad que obtiene al usar SwingWorker, pero lo mencionaré para completarlo.

Coloque dos campos donde ambos subprocesos pueden verlos: un booleano, llamado hasValue , inicializado en falso y uno int (o largo) llamado countValue . Ambos deben declararse como volatile . Cuando el hilo del contador está listo, pon el recuento en countValue . Luego configure hasValue en true. El hilo de la división puede verificar `hasValue ‘periódicamente y tomar el conteo cuando esté disponible.

Si la división proporciona valores que serán más precisos una vez que obtiene el recuento, esto servirá. Lo más probable es que esté haciendo un poco de trabajo y luego esperando el conteo. En este caso, configure un tercer campo llamado countMonitor , definido como final Object . Cuando termine el trabajo inicial, hasValue que verifique tiene hasValue . Si es verdad, toma el valor y continúa. Si es falso, llame al método de wait en countMonitor y continúe cuando se le notifique. El hilo del contador, cuando notifyAll , siempre debe llamar al método countMonitor en countMonitor después de poner los valores en hasValue y countValue .

Me he quedado un poco aquí. El javadoc para Object le informará sobre la sincronización necesaria y las excepciones marcadas. Su diseño es lo suficientemente directo como para no tener problemas con las historias de horror sobrenaturales habituales que genera el multihilo. Espero. Pero es posible que desee investigar un poco si toma esta ruta. (Si repite todo el proceso en la misma sesión, definitivamente querrá investigar mucho ).