2016-08-21 4 views
2

ScheduledThreadPoolExecutor (qui implémente ScheduledExecutorService) semble exécuter uniquement la classe SwingWorker une fois lors de l'utilisation de la méthode ScheduleAtFixedRate. Le code d'origine est un peu long, j'ai donc fait un nouveau code qui produit les mêmes résultats ci-dessous.ScheduledThreadPoolExecutor exécute uniquement Swingworker une fois

import java.util.concurrent.ScheduledThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

public class ScheduledThreadPoolExecutorTest extends SwingWorker<Void, Void>{ 
    @Override 
    protected Void doInBackground() { 
     System.out.println("Yay!"); 
     return null; 
    } 

    @Override 
    protected void done() { 
     try { 
      get(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Woohoo!"); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); 
       executor.scheduleAtFixedRate(new ScheduledThreadPoolExecutorTest(), 0, 30, TimeUnit.MILLISECONDS); 
      } 
     }); 
    } 
} 

Cela donne les résultats:

Yay! 
Woohoo! 

Pourquoi ScheduledThreadPoolExecutor en cours d'exécution SwingWorker une seule fois? Et que puis-je faire pour que le SwingWorker soit exécuté toutes les 30 millisecondes comme indiqué dans le code?

Répondre

3

Alors que SwingWorker n'implémente l'interface Runnable, par sa section API sur la méthode doInBackground():

Notez que cette méthode est exécutée une seule fois.

Ainsi, alors que sa méthode run() interne peut à plusieurs reprises exécuter, le doInBackground() ne fonctionnera qu'une seule fois. Non seulement cela, mais la méthode run() est marquée final dans SwingWorker, et donc vous ne pouvez pas le remplacer pour appeler doInBackground plusieurs fois.

Une meilleure solution n'est pas du tout d'utiliser un SwingWorker mais plutôt une classe plus simple dérivée de Runnable.

+0

Donc 'doInBackground()' est seulement appelé une fois par classe et pas une fois par instance de cette classe? Et aussi, que se passe-t-il si vous devez absolument utiliser SwingWorker parce que vous utilisez des objets Swing et que vous devez appeler 'repaint()' (non représenté ici, bien sûr, mais dans le code original)? – ICanCYou

+0

@ICanCYou: ça s'appelle une fois par instance - vous ne créez qu'une seule instance. –

+0

@ICanCYou: vous pouvez également créer plusieurs SwingWorkers en cas de besoin ou faire la file d'attente Swing appelle sur le thread d'événement en utilisant SwingUtilieis. Notez que 'repaint()' n'a pas besoin d'être appelé sur le thread d'événement. –

2

SwingWorker extends Runnable, cependant, il utilise FutureTask pour exécuter son calcul.

De la javadoc:

A cancellable asynchronous computation. This class provides a base 
implementation of {@link Future}, with methods to start and cancel 
a computation, query to see if the computation is complete, and 
retrieve the result of the computation. The result can only be 
retrieved when the computation has completed; the {@code get} 
methods will block if the computation has not yet completed. Once 
the computation has completed, the computation cannot be restarted 
or cancelled (unless the computation is invoked using 
{@link #runAndReset}). 

C'est, le FutureTask fonctionnera qu'une seule fois, si vous essayez de l'exécuter à nouveau, il suffit de retourner.

public void run() { 
    if (state != NEW || 
     !UNSAFE.compareAndSwapObject(this, runnerOffset, 
            null, Thread.currentThread())) 
     return; 
    try { 
     Callable<V> c = callable; 
     if (c != null && state == NEW) { 
      V result; 
      boolean ran; 
      try { 
       result = c.call(); 
       ran = true; 
      } catch (Throwable ex) { 
       result = null; 
       ran = false; 
       setException(ex); 
      } 
      if (ran) 
       set(result); 
     } 
    } finally { 
     // runner must be non-null until state is settled to 
     // prevent concurrent calls to run() 
     runner = null; 
     // state must be re-read after nulling runner to prevent 
     // leaked interrupts 
     int s = state; 
     if (s >= INTERRUPTING) 
      handlePossibleCancellationInterrupt(s); 
    } 
}