2009-08-05 433 views

回答

3

通常,我只是從線程代碼中定期輪詢一個控制對象。喜歡的東西:

interface ThreadControl { 
    boolean shouldContinue(); 
} 

class Timer implements ThreadControl { 
    public boolean shouldContinue() { 
     // returns false if max_time has elapsed 
    } 
} 

class MyTask implements Runnable { 
    private tc; 
    public MyTask(ThreadControl tc) { 
     this.tc = tc; 
    } 
    public void run() { 
     while (true) { 
      // do stuff 
      if (!tc.shouldContinue()) 
       break; 
     } 
    } 
} 
5

如何:

提交您CallableExecutorService和保持一個句柄返回Future

ExecutorService executorService = ... // Create ExecutorService. 
Callable<Result> callable = new MyCallable(); // Create work to be done. 
Future<Result> fut = executorService.submit(callable); 

裹在Delayed一個實現由此DelayedgetDelay(TimeUnit)方法返回所討論的工作的最大執行時間Future

public class DelayedImpl<T> implements Delayed { 
    private final long maxExecTimeMillis; 
    private final Future<T> future; 

    public DelayedImpl(long maxExecTimeMillis, Future<T> future) { 
    this.maxExecMillis = maxExecMillis; 
    this.future = future; 
    } 

    public TimeUnit getDelay(TimeUnit timeUnit) { 
    return timeUnit.convert(maxExecTimeMillis, TimeUnit.MILLISECONDS); 
    } 

    public Future<T> getFuture() { 
    return future; 
    } 
} 

DelayedImpl impl = new DelayedImpl(3000L, fut); // Max exec. time == 3000ms. 

Add the `DelayedImpl` to a `DelayQueue`. 

Queue<DelayedImpl> queue = new DelayQueue<DelayImpl>(); 
queue.add(impl); 

從隊列中有一個線程反覆take()和檢查每個DelayedImplFuture是否是通過調用isDone()完整的;如果不是,則取消該任務。

new Thread(new Runnable() { 
    public void run() { 
    while (!Thread.interrupted) { 
     DelayedImpl impl = queue.take(); // Perform blocking take. 
     if (!impl.getFuture().isDone()) { 
     impl.getFuture().cancel(true); 
     } 
    } 
    } 
}).start(); 

主要優點這種方法是,你可以設置每個任務和延遲隊列不同的最長執行時間會自動的執行時間量最小剩餘返回任務。

+0

引發TimeoutException的Future.get(long timeout,TimeUnit unit)肯定會這樣做嗎?我認爲在這個例外情況下,你可以調用future.cancel(true)... – JeeBee 2009-10-08 12:30:13

+0

Future.get(long,TimeUnit)將會阻塞一段指定的時間來完成特定的*未來。但是,我添加的解決方案允許您在單個線程中檢查*所有*可加密進程,而不是*阻止特定的進程。 假設我提交了一個需要5分鐘的Callable,在我的「檢查」線程中,我調用future.get(5L,TimeUnit.MINUTES)。然後提交另一個Callable,最大執行時間爲10秒。但是,線程不會查看第二個Callable是否已經運行了大於10秒,直到返回前一個阻塞調用。 – Adamski 2009-10-08 14:16:46

4

亞當斯基:

我相信你的延遲接口的實現需要以正常工作的一些調整。如果從對象的實例化過去的時間量超過了最大生命週期,那麼'getDelay()'的返回值應該返回一個負值。爲了達到這個目的,你需要存儲創建任務的時間(可能開始)。然後每次'getDelay()'被調用時,計算是否超出了線程的最大生命週期。如:

class DelayedImpl<T> implements Delayed { 

    private Future<T> task; 
    private final long maxExecTimeMinutes = MAX_THREAD_LIFE_MINUTES; 
    private final long startInMillis = System.currentTimeMillis(); 

    private DelayedImpl(Future<T> task) { 
     this.task = task; 
    } 

    public long getDelay(TimeUnit unit) { 
     return unit.convert((startInMillis + maxExecTimeMinutes*60*1000) - System.currentTimeMillis(), TimeUnit.MILLISECONDS); 
    } 

    public int compareTo(Delayed o) { 
     Long thisDelay = getDelay(TimeUnit.MILLISECONDS); 
     Long thatDelay = o.getDelay(TimeUnit.MILLISECONDS); 
     return thisDelay.compareTo(thatDelay); 
    } 

    public Future<T> getTask() { 
     return task; 
    } 
}