SwingWorker no responde

¿Qué estoy tratando de hacer?

Al hacer clic en Start JButton , se ejecutará SwingWorker . Dentro del método doInBackground() , paso cada índice de arrNames , al método publish() , para que pueda mostrarse dentro de JTextArea .

Que pasó ?

Si no guardo la línea System.out.format("Counter : %d%n", counter); como comentario , en mi método doInBackground() del SwingWorker , entonces SwingWorker funciona como se esperaba . Aunque si lo comento , entonces SwingWorker deja de responder .

Estoy haciendo algo mal ?


Versión de Java:

 java version "1.7.0_25" Java(TM) SE Runtime Environment (build 1.7.0_25-b16) Java HotSpot(TM) Client VM (build 23.25-b01, mixed mode, sharing) 

Aquí está el código que estoy usando:

 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class SwingWorkerExample1 { private JLabel statusLabel; private JTextArea tArea; private JButton startButton; private JButton stopButton; private BackgroundTask backgroundTask; private ActionListener buttonActions = new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { JButton source = (JButton) ae.getSource(); if (source == startButton) { startButton.setEnabled(false); stopButton.setEnabled(true); backgroundTask = new BackgroundTask(); backgroundTask.execute(); } else if (source == stopButton) { backgroundTask.cancel(true); stopButton.setEnabled(false); startButton.setEnabled(true); } } }; private void displayGUI() { JFrame frame = new JFrame("Swing Worker Example"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); JPanel contentPane = new JPanel(); contentPane.setBorder( BorderFactory.createEmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(5, 5)); statusLabel = new JLabel("Status Bar", JLabel.CENTER); tArea = new JTextArea(20, 20); tArea.setWrapStyleWord(true); tArea.setLineWrap(true); JScrollPane textScroller = new JScrollPane(); textScroller.setBorder( BorderFactory.createTitledBorder("Textual OUTPUT : ")); textScroller.setViewportView(tArea); startButton = new JButton("Start"); startButton.addActionListener(buttonActions); stopButton = new JButton("Stop"); stopButton.setEnabled(false); stopButton.addActionListener(buttonActions); JPanel buttonPanel = new JPanel(); buttonPanel.add(startButton); buttonPanel.add(stopButton); contentPane.add(statusLabel, BorderLayout.PAGE_START); contentPane.add(textScroller, BorderLayout.CENTER); contentPane.add(buttonPanel, BorderLayout.PAGE_END); frame.setContentPane(contentPane); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } private class BackgroundTask extends SwingWorker { private int counter = 0; private String[] arrNames = { "US Rates Strategy Cash", "Pavan Wadhwa(1-212) 844-4597", "Srini Ramaswamy(1-212) 844-4983", "Meera Chandan(1-212) 855-4555", "Kimberly Harano(1-212) 823-4996", "Feng Deng(1-212) 855-2555", "US Rates Strategy Derivatives", "Srini Ramaswamy(1-212) 811-4999", "Alberto Iglesias(1-212) 898-5442", "Praveen Korapaty(1-212) 812-3444", "Feng Deng(1-212) 812-2456", "US Rates Strategy Derivatives", "Srini Ramaswamy(1-212) 822-4999", "Alberto Iglesias(1-212) 822-5098", "Praveen Korapaty(1-212) 812-3655", "Feng Deng(1-212) 899-2222" }; public BackgroundTask() { statusLabel.setText((this.getState()).toString()); System.out.println(this.getState()); } @Override protected Void doInBackground() { statusLabel.setText((this.getState()).toString()); System.out.println(this.getState()); while (!isCancelled()) { counter %= arrNames.length; //System.out.format("Counter : %d%n", counter); publish(arrNames[counter]); counter++; } statusLabel.setText((this.getState()).toString()); System.out.println(this.getState()); return null; } @Override protected void process(java.util.List messages) { for (String message : messages) tArea.append(String.format(message + "%n")); } } public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { new SwingWorkerExample1().displayGUI(); } }; EventQueue.invokeLater(runnable); } } 

EDIT 1:

Como se sugiere, si agrego Thread.sleep(...) , funciona, sin embargo, arroja una InterruptedException como se muestra a continuación. Entonces el truco funciona Pero, ¿es esta la forma legítima de realizarlo?

 C:\Mine\JAVA\J2SE\classes>java SwingWorkerExample1 PENDING STARTED java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at SwingWorkerExample1$BackgroundTask.doInBackground(SwingWorkerExample1.java:108) at SwingWorkerExample1$BackgroundTask.doInBackground(SwingWorkerExample1.java:76) at javax.swing.SwingWorker$1.call(SwingWorker.java:296) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at javax.swing.SwingWorker.run(SwingWorker.java:335) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:724) DONE 

EDICION 2:

Solo se doInBackground() , que generó la excepción anterior:

 @Override protected Void doInBackground() { Runnable runnable = new Runnable() { @Override public void run() { statusLabel.setText((BackgroundTask.this.getState()).toString()); } }; EventQueue.invokeLater(runnable); System.out.println(this.getState()); while (!isCancelled()) { counter %= arrNames.length; //System.out.format("Counter : %d%n", counter); publish(arrNames[counter]); try {Thread.sleep(30);} catch(InterruptedException ie) {ie.printStackTrace();} counter++; } runnable = new Runnable() { @Override public void run() { statusLabel.setText((BackgroundTask.this.getState()).toString()); } }; EventQueue.invokeLater(runnable); System.out.println(this.getState()); return null; } 

si agrego Thread.sleep (…), funciona, sin embargo, arroja una excepción InterruptedException

El código que aparentemente produce la excepción (copiado de la edición de OP):

 while (!isCancelled()) { counter %= arrNames.length; // System.out.format("Counter : %d%n", counter); publish(arrNames[counter]); try { Thread.sleep(30); // throws } catch (InterruptedException ie) { ie.printStackTrace(); } counter++; } 

La razón, sin embargo, es el código que cancela al trabajador (en el actionListener):

 backgroundTask.cancel(true); 

que explícitamente le dice al trabajador que cancele al … interrumpir el hilo. De su api doc:

mayInterruptIfRunning: verdadero si el hilo que ejecuta esta tarea debe interrumpirse; de lo contrario, las tareas en progreso pueden completarse

Como un aparte: capturar la excepción y no hacer nada (ignorando efectivamente la interrupción) no es la mejor de las ideas. Probablemente no sea demasiado perjudicial en este caso, debido a la verificación del estado cancelado. Las implementaciones típicas de los trabajadores atrapan y regresan, después de hacer alguna limpieza interna si es necesario, o no lo manejan en absoluto.

Amplificando en las otras respuestas, no actualice la GUI de su hilo de fondo, que bloquea el EDT, y no intente evitar el problema con invokeLater() . En su lugar, publish() el resultado deseado y actualice tanto statusLabel como tArea en process() , como se sugiere a continuación. Para las pruebas, Thread.sleep(100) simula una latencia pequeña, pero puede usar Thread.yield() , como se muestra aquí . También puede actualizar la GUI en un PropertyChangeListener , como se muestra aquí .

 import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.event.*; import javax.swing.*; public class SwingWorkerExample1 { private JLabel statusLabel; private JTextArea tArea; private JButton startButton; private JButton stopButton; private BackgroundTask backgroundTask; private ActionListener buttonActions = new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { JButton source = (JButton) ae.getSource(); if (source == startButton) { startButton.setEnabled(false); stopButton.setEnabled(true); backgroundTask = new BackgroundTask(); backgroundTask.execute(); } else if (source == stopButton) { backgroundTask.cancel(true); stopButton.setEnabled(false); startButton.setEnabled(true); } } }; private void displayGUI() { JFrame frame = new JFrame("Swing Worker Example"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); JPanel contentPane = new JPanel(); contentPane.setBorder( BorderFactory.createEmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(5, 5)); statusLabel = new JLabel("Status Bar", JLabel.CENTER); tArea = new JTextArea(20, 20); tArea.setWrapStyleWord(true); tArea.setLineWrap(true); JScrollPane textScroller = new JScrollPane(); textScroller.setBorder( BorderFactory.createTitledBorder("Textual OUTPUT : ")); textScroller.setViewportView(tArea); startButton = new JButton("Start"); startButton.addActionListener(buttonActions); stopButton = new JButton("Stop"); stopButton.setEnabled(false); stopButton.addActionListener(buttonActions); JPanel buttonPanel = new JPanel(); buttonPanel.add(startButton); buttonPanel.add(stopButton); contentPane.add(statusLabel, BorderLayout.PAGE_START); contentPane.add(textScroller, BorderLayout.CENTER); contentPane.add(buttonPanel, BorderLayout.PAGE_END); frame.setContentPane(contentPane); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } private class BackgroundTask extends SwingWorker { private int counter = 0; private String[] arrNames = {"US Rates Strategy Cash", "Pavan Wadhwa(1-212) 844-4597", "Srini Ramaswamy(1-212) 844-4983", "Meera Chandan(1-212) 855-4555", "Kimberly Harano(1-212) 823-4996", "Feng Deng(1-212) 855-2555", "US Rates Strategy Derivatives", "Srini Ramaswamy(1-212) 811-4999", "Alberto Iglesias(1-212) 898-5442", "Praveen Korapaty(1-212) 812-3444", "Feng Deng(1-212) 812-2456", "US Rates Strategy Derivatives", "Srini Ramaswamy(1-212) 822-4999", "Alberto Iglesias(1-212) 822-5098", "Praveen Korapaty(1-212) 812-3655", "Feng Deng(1-212) 899-2222"}; public BackgroundTask() { statusLabel.setText((this.getState()).toString()); } @Override protected Void doInBackground() { while (!isCancelled()) { counter %= arrNames.length; publish(arrNames[counter]); counter++; try { Thread.sleep(100); // simulate latency } catch (InterruptedException ex) { publish("Cancelled: " + isCancelled()); } } return null; } @Override protected void process(java.util.List messages) { statusLabel.setText((this.getState()).toString()); for (String message : messages) { tArea.append(String.format(message + "%n")); } } } public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { new SwingWorkerExample1().displayGUI(); } }; EventQueue.invokeLater(runnable); } } 

comentarios

  • @kleopatra que es un error de documentación, corregido en jdk7 al menos :-), por favor, ¿cuál de los JDKs se muestran esos errores a partir del carrusel …,

  • wait / notify es para hilo, SwingWorker is Future, muy mal implementado, significa sin notificadores, pones algo en el tubo y esperas en otro lado,

  • parece que no hay nada entre un lado y el otro de este tubo, esta es la razón por la que traté de invocar Thread, Runnable, Executor (Runnable) desde doInBackground e ignorar publicar, procesar, configurar ProcessProcess

  • Otro problema divertido es obtener () y excepciones (s) todas las excepciones, no solo la 1ra. desde un lado y el otro de este tubo

  • hay dos formas de usar SwingWokrer

    1. trate de evitar el uso de SwingWorker

    2. utilice doInBackground como puente para thread de trabajadores, para que output use publish, process, setProcess, wait for done () y use done () como notificador para obtener una excepción, notificador que SwingWorker finalizó