2011-09-25 10 views
11

Il mio computer ha 4 core e sto eseguendo un programma Java swing gui. Quando eseguo la mia applicazione utilizza solo due core e circa il 30% di utilizzo della CPU. Ho un gran numero di file da elaborare e voglio dividerli in due thread per svolgere questa attività più velocemente utilizzando più cpu.Istanze di Swingworker non in esecuzione contemporaneamente

ho una classe SwingWorker chiamato PrepareTask, che ha un costruttore con due interi:

class PrepareTask extends SwingWorker<Void, Void> { 
    int start, end; 
    PrepareTask (int start, int end) { ... } 
    ... 
    public Void doInBackground() {... } 
    public void done() { ... } 

creo due istanze di questo come:

PrepareTask prepareTask = new PrepareTask(0,numberOfFiles/2); 
    prepareTask.execute(); 
    PrepareTask prepareTask2 = new PrepareTask(numberOfFiles/2, numberOfFiles); 
    prepareTask2.execute(); 

Entrambi sono lanciati (sembra), ma quando è in esecuzione, posso vedere (stampare gli stmts) che la prima preparazione deve terminare (stampare gli stmts all'interno) prima che inizi il secondo. E l'utilizzo della CPU è lo stesso di prima, circa il 30%. Entrambi prendono naturalmente i dati dalla stessa fonte, un DefaultTableModel.

Qualche idea su come fare questo o quello che sto facendo male? grazie.

+0

Si prega di notare che se la maggior parte del tempo di elaborazione comporta l'accesso ai file, quindi avere molti thread non renderà necessariamente più veloce perché il disco diventerà il collo di bottiglia. Puoi sviluppare ulteriormente il tipo di elaborazione che esegui su questi file? – jfpoilpret

risposta

16

Questo è il risultato di un cambiamento nel comportamento di SwingWorker da un aggiornamento di Java 6 a un altro. In realtà c'è una segnalazione di bug nel vecchio database dei bug di SUN per Java 6.

Quello che è successo è stato che SUN ha cambiato l'implementazione originale di SwingWorker dall'utilizzo di N thread, all'utilizzo di 1 thread con una coda illimitata. Pertanto non è possibile eseguire più due SwingWorkers contemporaneamente. (Questo crea anche uno scenario in cui si verifica un deadlock: se un swingworker attende un altro che attende il primo, un compito potrebbe entrare in un deadlock come risultato.)

Cosa si può fare per aggirare questo è utilizzare un ExecutorService e pubblicare FutureTasks su di esso. Questi forniranno il 99% dell'API SwingWorker (SwingWorker è un derivato di FutureTask), tutto ciò che devi fare è impostare correttamente il tuo Executor.

+1

L'ho già visto prima, ma lo hai riepilogato meglio della maggior parte degli altri: +1 –

+0

E questo dovrebbe essere risolto in Java SE 6u21: http://www.oracle.com/technetwork/java/javase/bugfixes6u21- 156339.html – keuleJ

+0

Questo è il bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6925575 – keuleJ

0

Forse Swing sta controllando la pianificazione dei thread? O forse SwingWorker ha una dimensione del pool di thread di 1 (non c'è alcuna descrizione in SwingWorker javadoc sull'esecuzione di più thread SwingWorker e suppongo che più thread possano causare alcuni problemi di concorrenza difficili in Swing).

Se tutto quello che vogliamo fare è eseguire alcune elaborazioni in parallelo, è possibile risolvere questo il modo semplice estendendo la Thread classe Java, implementazione run, chiamando SwingUtilities.invokeLater() alla fine di aggiornare l'interfaccia grafica con le eventuali modifiche:

class PrepareTask extends Thread 
    { 
     PrepareTask (int start, int end) { ... } 
     public void run() { ... ; SwingUtilities.invokeLater(new Runnable() { public void run() { do any GUI updates here })} 

iniziano i fili con:

prepareTask.start(); 

O forse qualcosa nel vostro modello di dati è single-thre pubblicizzato e bloccando il secondo thread? In tal caso, è necessario risolvere il problema con il modello di dati.

Problemi correlati