Domanda

Ho una piccola applicazione di elaborazione delle immagini che fa più cose in una volta usando SwingWorker. Tuttavia, se corro il seguente codice (estratto semplificato), appende appena il JDK 7 B70 (finestre), ma lavora in 6u16. Si inizia un nuovo lavoratore all'interno di un altro lavoratore e attende il suo risultato (la vera applicazione esegue più sotto-lavoratori e attende per tutti in questo modo). Ho usato alcuni modelli sbagliati qui (come in gran parte v'è di 3-5 lavoratori della SwingWorker-piscina, che ha limite del 10 credo)?

import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class Swing {
       static SwingWorker<String, Void> getWorker2() {
               return new SwingWorker<String, Void>() {
                       @Override
                       protected String doInBackground() throws Exception {
                               return "Hello World";
                       }
               };
       }
       static void runWorker() {
               SwingWorker<String, Void> worker 
                   = new SwingWorker<String, Void>() {
                       @Override
                       protected String doInBackground() throws Exception {
                               SwingWorker<String, Void> sw2 = getWorker2();
                               sw2.execute();
                               return sw2.get();
                       }
               };
               worker.execute();
               try {
                       System.out.println(worker.get());
               } catch (Exception e) {
                       e.printStackTrace();
               }
       }
       public static void main(String[] args) {
               SwingUtilities.invokeLater(new Runnable() {
                       @Override
                       public void run() {
                               runWorker();
                       }
               });
       }

}
È stato utile?

Soluzione

Come nessuno ha sparato fuori il link eppure, sembra che questo è in realtà un bug noto:

http://bugs.sun.com/bugdatabase/view_bug.do? bug_id = 6880336

Sorprendentemente ci sono meno di 100 voti per quello che dovrebbe essere un bug showstopper per la maggior parte delle applicazioni non banali.

Altri suggerimenti

I tuoi SwingWorkers vengono eseguiti nel tuo thread SwingWorker. Quindi, quando si vede

  

Sembra che pende sulla sw2.get () e non v'è un solo swingworker- chiamato thread nel jdk7. Su JDK6, vedo 3-5 in una sola volta. - kd304

Questo è perché la classe SwingWorker non è un filo, ma un compito da eseguire su un thread, e la configurazione di default per l'ExecutorService per SwingWorker in Java 6 è configurato diverso da quello in Java 7. IE tua SwingWorkerExecutorService ( che è definito all'interno della classe SwingWorker) ha un valore differente per il numero massimo di thread da allocare ai compiti.

//From Java 6 SwingWorker

private static final int MAX_WORKER_THREADS = 10;

public final void execute() {
    getWorkersExecutorService().execute(this);
}

private static synchronized ExecutorService getWorkersExecutorService() {
...
private static synchronized ExecutorService getWorkersExecutorService() {
new ThreadPoolExecutor(0, MAX_WORKER_THREADS,
                                     1L, TimeUnit.SECONDS,
                                     new LinkedBlockingQueue<Runnable>(),
                                     threadFactory)
}

Hai solo l'un thread in esecuzione dei compiti SwingWorker, e che il primo compito è in attesa del completamento del secondo compito, che non può essere eseguito, perché il filo il secondo compito sarebbe stato eseguito su è in attesa per la seconda compito di completare prima che tornerà. Rendendo il filo SwingWorker dipende l'esecuzione di un altro è un percorso sicuro di deadlock. Si consiglia di guardare con un ExecutorService di pianificare eventi da eseguire sul filo SwingWorker, e non fare un evento in programma dipende dalla conclusione di un altro evento pianificato.

  

Java 7 SwingWorker

Guardando il codice sorgente per SwingWorker, sembra un ExecutorService viene utilizzato come un pool di thread di lavoro. E 'possibile che il tipo di ExecutorService utilizzato è cambiato tra il Java 6 e Java 7. Sembra che il codice verrà deadlock se l'ExecutorService riesce solo esattamente 1 thread alla volta (come ti sembra di avere notato).

Questo perché il 'sw2.get ()' chiamata bloccherà il thread corrente, che è lo stesso filo SW2 cercheranno di usare. SW2 non può mai eseguito perché il primo operaio sta bloccando.

Credo che la soluzione migliore è quella di cambiare la logica in modo che non si chiama catene di lavoratori swing come questo.

Prima di aggiornamento JDK 18 è possibile eseguire:

public static void main(String[] args) {

    new SwingWorker<Void, Void>() {
        @Override
        protected Void doInBackground() throws Exception {
            System.out.println("ok");
            return null;
        }
    }.execute();

}

Questo codice non funziona più, semplicemente perché SwingWorkers devono essere eseguite sul EDT.

Di conseguenza, non è possibile annidare SwingWorkers (SW2 sarete mai a corto in voi codice di esempio in JDK più recenti).

Credo che la sostituzione swingWorkers nidificate con ExecutorService java.util.concurrent.Future chiama è una buona soluzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top