16

運行任務本身內停止週期性任務是否有一個很好的方式在ScheduledExecutorService的運行時,從任務本身停止任務的重複?從一個ScheduledExecutorService的

比方說,我有以下任務:

Future<?> f = scheduledExecutor.scheduleAtFixedRate(new Runnable() { 
    int count = 0; 
    public void run() { 
     System.out.println(count++); 
     if (count == 10) { 
      // ??? cancel self 
     } 
    } 
}, 1, 1, TimeUnit.SECONDS); 

從外面,很容易通過f.cancel()取消,但我怎麼能停在指定的地點重複? (通過AtomicReference傳遞未來是不安全的,因爲當scheduleAtFixedRate返回f late並且變量設置得太晚,並且任務本身可能已經運行時,可能會看到參考中的空值)。

+0

爲什麼不拋出StopIteration異常,您可以通過它從外部刪除執行程序的調用?據我所知,Callable's不知道他們加入的任何執行者。 – Tim 2011-02-05 21:46:01

+0

最簡單和相當醜陋的方式是拋出異常:) – bestsss 2011-02-06 00:05:06

回答

11

當一個重複的任務拋出一個異常或錯誤時,它被放置在未來中,任務不再重複。你可以拋出一個RuntimeException或你選擇的錯誤。

+1

是的,這是一個選項。我希望有一個更優雅的解決方案。 – akarnokd 2011-02-05 22:33:11

+3

這是做到這一點的最佳方式。如果你想讓它「很漂亮」,聲明一個擴展了RuntimeException的類,它正確地描述了TaskComplete的用途。 – 2011-02-06 00:05:22

2

好像壞設計了Runnable知道它在運行任何遺囑執行人,或拋出一個錯誤,如果達到10不是錯誤狀態是一個黑客。

你可以做循環的調度和執行的10之外?這可能需要使用非調度執行程序,因爲您將自己手動調度它們。

4

而不是使用匿名內部類,您可以使用一個命名的類,然後可以有一個屬性爲Future對象,當您計劃任務時從Executor獲得。

abstract class FutureRunnable implements Runnable { 

    private Future<?> future; 

    /* Getter and Setter for future */ 

} 

當您計劃任務你就可以通過FutureRunnable

FutureRunnable runnable = new FutureRunnable() { 

    public void run() { 
     if (/* abort condition */) 
      getFuture().cancel(false); 
    } 

}; 
Future<?> future = executor.scheduleAtFixedRate(runnable, ...); 
runnable.setFuture(future); 

也許你將不得不作出肯定的是,該任務不是Future已經設置之前執行,否則你會得到一個NullPointerException

1

這裏是另一種方式,那就是即使線程安全的;

final Future<?>[] f = {null}; 
    f[0]= scheduledExecutor.scheduleAtFixedRate(new Runnable() { 
     int count = 0; 
     public void run() { 

      System.out.println(count++); 
      if (count == 10) { 
       Future<?> future; 
       while(null==(future = f[0])) Thread.yield();//prevent exceptionally bad thread scheduling 
       future.cancel(false); 
       return; 
       //cancel self 
      } 
     } 
    }, 1, 1, TimeUnit.SECONDS); 
1

剛看到這個現在...因爲我想做同樣的事情...這裏是我的解決方案,我懷疑這是線程安全的。

首先創建面向未來的容器:

public static class Cancel { 
    private ScheduledFuture<?> future; 

    public synchronized void setFuture(ScheduledFuture<?> future) { 
     this.future = future; 
    } 

    public synchronized void stop() { 
     LOG.debug("cancelling {}", future); 
     future.cancel(false); 
    } 
} 

然後未來代碼:

final Cancel controller = new Cancel(); 

    synchronized (controller) { 
     ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay(() -> { 
      if (<CONTINUE RUNNING CONDITION) { 

      } else { 
       // STOP SCHEDULABLE FUTURE 
       controller.stop(); 
      } 
     }, startTime, timeBetweenVisbilityChecks); 
     controller.setFuture(future); 
    } 
} 

所以注意一下,直到未來已創建站將不會調用與未來已經設置在控制器上。

請記住,Runnable是異常的內部類,它將在不同的線程中運行。