2016-08-21 41 views
2

ScheduledThreadPoolExecutor(實現ScheduledExecutorService)在使用ScheduleAtFixedRate方法時似乎只運行一次SwingWorker類。原來的代碼有點長,所以我做了一個新的代碼,在下面產生相同的結果。ScheduledThreadPoolExecutor只運行Swingworker一次

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); 
      } 
     }); 
    } 
} 

這樣產生的結果:

Yay! 
Woohoo! 

爲什麼的ScheduledThreadPoolExecutor運行的SwingWorker只有一次?我能做些什麼來使SwingWorker每30毫秒運行一次,如代碼中所示?

回答

3

雖然SwingWorker的確實實現了Runnable接口,其每節APIdoInBackground()方法:

注意,此方法只執行一次。

所以雖然它的內部run()方法可能會反覆運行,但doInBackground()只能運行一次。不僅如此,run()方法在SwingWorker中標記爲final,因此您無法覆蓋它以多次調用doInBackground

更好的解決方案是根本不使用SwingWorker,而是使用更簡單的Runnable派生類。

+0

因此'doInBackground()'只被調用一次每個類而不是每個類的實例一次?另外,如果你完全需要使用SwingWorker,因爲你正在使用Swing對象,並且需要調用'repaint()'(當然這裏沒有顯示,但是在原始代碼中)? – ICanCYou

+0

@ICanCYou:每個實例調用一次 - 您只是創建一個實例。 –

+0

@ICanCYou:如果需要,也可以創建多個SwingWorkers,或者可以使用SwingUtilieis將Swing調用隊列到事件線程中。注意''repaint()'不需要在事件線程上調用。 –

2

SwingWorker擴展了Runnable,但是它使用FutureTask來運行它的計算。

根據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}). 

也就是說,FutureTask將只運行一次,如果你嘗試再次運行它,它會簡單地返回。

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); 
    } 
}