Pregunta

He realizado una aplicación de cambios pero hay un problema en esto que es el siguiente:

He iniciado un hilo de SwingWorker llamado " Thread-Main " del evento Dispatch Thread y he pasado una referencia JLabel de la GUI a " Thread-Main " ;.

Ahora he comenzado 10 hilos desde " Thread-Main " ;.

Ahora quiero que los 10 subprocesos actualicen JLabel.

¿Cómo puedo hacer eso?

Alguien me dijo que puedo hacer esto haciendo primero todas las subclases de 10 hilos de SwingWorker y luego llamando al método de publicación (& "; &";) y pasando la cadena en ese & "; publicar " y luego recopilar todas las cadenas publicadas por el siguiente método en " Thread-Main "

@Override
protected void process(List<String> labelStrings) {
    String count = labelStrings.get(labelStrings.size() - 1);
    label.setText(count); // label is a reference to a label in the GUI 
}
  1. ¿Es correcto el enfoque anterior para hacer eso?
  2. ¿Deberían los 10 hilos ser subclases de SwingWorker?
  3. ¿Hay alguna otra forma de hacer eso?
¿Fue útil?

Solución

  1. No : este es el enfoque incorrecto si desea controlar el número de subprocesos usted mismo. ¿Por qué? Porque si observa el código SwingWorker verá que usa un ThreadPoolExecutor que contiene internamente un máximo de 10 hilos. Si inicia una cantidad de doInBackground() simultáneamente, todos se ejecutarán usando este ejecutor. Sin embargo, no tiene control directo sobre si los hilos de fondo se ejecutan en paralelo .
  2. Ver punto 1.
  3. Mi solución recomendada sería:

    • Cree un solo ExecutorService.
    • Dentro del método CountDownLatch inicie 10 hilos directamente o usando un CompletionService.
    • Use un Callable<String> o String para sincronizar entre su hilo maestro (es decir, JLabel hilo de fondo) y los hilos de trabajo.

Ejemplo

Defina el número de hilos de trabajo para invocar y declare que JLabel se actualizará.

final int nThreads = 10;
JLabel myLbl = new JLabel();

Defina la unidad de trabajo que deseamos ejecutar como done(). El resultado Void se usará para actualizar el process(String... chunks).

private static class MyCallable implements Callable<String> {
  public String call() { ... }
}

Ahora inicie un <=>, que a su vez iniciará a varios trabajadores paralelos para realizar cualquier procesamiento. El trabajador no devolverá un resultado a través de la llamada a <=> (de ahí el tipo <=>) pero volverá a ordenar resultados intermedios <=> en el hilo Swing llamando al <=>.

new SwingWorker<Void, String>() {
  // See method definitions below.
}.execute();

Defina <=> para iniciar los subprocesos de trabajo y bloquear para cada resultado usando un <=>.

public Void doInBackground() throws Exception {
  // Define executor service containing exactly nThreads threads.
  ExecutorService execService = Executors.newFixedThreadPool(nThreads);


  // Define completion service that will contain the processing results.
  CompletionService compService = new ExecutorCompletionService(execService);    

  // Submit work to thread pool using the CompletionService.  Future<String>
  // instances will be added to the completion service's internal queue until complete.
  for (int i=0; i<nThreads; ++i) {
    compService.submit(new MyCallable());
  }

  // Take results from each worker as they appear and publish back to Swing thread.
  String result;
  while ((result = compService.take().get()) != null) {
    publish(result);
  }
}

Ahora implementamos <=> simplemente para actualizar el <=> cuando se llama.

public void process(String... chunks) {
  if (chunks.length > 0) {
    // Update label with last value in chunks in case multiple results arrive together.
    myLbl.setText(chunks[chunks.length - 1]);
  }
}

Finalmente, anulamos <=> para ordenar cualquier excepción en el hilo Swing.

public void done() {
  try {
    get(); // Will return null (as per Void type) but will also propagate exceptions.
  } catch(Exception ex) {
    JOptionPane.show ... // Show error in dialog.
  }
}

Otros consejos

Quizás un enfoque más fácil es envolver el código que actualiza la GUI en un método SwingUtilities.invokeLater (...).

Editar: en sus hilos individuales cada vez que desee actualizar la etiqueta que hace:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        label.setText(...);
    }
});

¿por qué necesitas 10 hilos? ¿por qué no lo hará un hilo adicional?

la verdadera pregunta: ¿cuál es el problema que está tratando de resolver?

para responder sus preguntas directas:

1) sí, ese es el enfoque correcto 2) sí, los subprocesos deben ser SwingWorkers (si está utilizando netbeans, también puede usar Tareas, que también son subclases de SwingWorker)

3) si desea tener un hilo separado del edt; entonces necesitas usar un swingworker; así que esa es la forma de hacerlo.

¡buena suerte!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top