2012-11-09 90 views
4

試圖構建Runnable必須在給定的時間限制內結束。可運行時間限制

當前我正在使用java.util.Timer中斷Runnable線程。

TimerRunnable開始後立即開始。

import java.util.Timer; 
import java.util.TimerTask; 

public class test { 
    Thread task; 
    Timer timer; 

    public void start(){ 

     task = new Thread(new worker()); 
     timer = new Timer("timer",true); 

     task.start(); 
     timer.schedule(new Terminator(),1000*2); 
    } 


    class worker implements Runnable{ 
     @Override 
     public void run() { 

      for (int i = 0 ; i < 2; i++){ 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        System.out.println("Test Interrupted !!"); 
        return; 
       } 
      } 

      System.out.println("Test Finished !!"); 
      timer.cancel(); 
     } 
    } 

    class Terminator extends TimerTask{ 
     @Override 
     public void run() { 
      task.interrupt(); 
      System.out.println("Test Terminated !!"); 
     } 
    } 
} 

但我懷疑這會導致競爭條件TimerRunnable線程之間: Runnable即將完成,並Timer也燒成。

這可以導致這兩個成品!!終止!正在打印?如果是這樣,如何避免它?

更新:

它發生:

11-09 21:14:40.741: INFO/System.out(31442): Test Finished !! 18 
11-09 21:14:40.751: INFO/System.out(31442): Test Terminated !! 18 
11-09 21:14:40.751: INFO/System.out(31442): Test Finished !! 19 
11-09 21:14:40.751: INFO/System.out(31442): Test Terminated !! 19 
+2

不回答你的問題,但是看看['TimeLimiter'(HTTP://docs.guava-libraries .googlecode.com/git/javadoc/com/google/common/util/concurrent/TimeLimiter.html)[tag:guava] –

+0

@TomaszNurkiewicz謝謝。 –

回答

4

可這個不斷導致兩個成品!並終止!正在印刷?

是的。當打印「完成」信息時,定時器可能會在取消之前觸發。

System.out.println("Finished !!"); 
// The timer can fire here. 
timer.cancel(); 

如果發生這種情況,將會打印這兩條消息。


要避免此問題,您可以使用同步。

synchronized (someObject) { 
    if (!finished) { 
     finished = true; 
     System.out.println("Finished !!"); 
     timer.cancel(); 
    } 
} 

而在終止子:

synchronized (someObject) { 
    if (!finished) { 
     finished = true; 
     task.interrupt(); 
     System.out.println("Test Terminated !!"); 
    } 
} 

這防止形成被打印兩個消息。

+0

請注意,'finished'必須是'volatile'。 –

+0

謝謝。我最終用一個簡單的'if(ended.compareAndSet(false,true))'來檢查'AtomicBoolean''''''''''''',代替同步塊。 –

4

是的。如果你想避免這種情況,你需要使用synchronize和共享鎖對象:

public class test { 
    private Object lock = new Object(); 
    ... 

     synchronized(lock) { 
      System.out.println("Test Finished !!"); 
      timer.cancel(); 
     } 
    ... 

     synchronized(lock) { 
      if(! task.isRunning()) return; 

      task.interrupt(); 
      System.out.println("Test Terminated !!"); 
     } 

    ... 
+1

這是一種挑剔的行爲,但是在進入'synchronized()'塊和*實際任務結束*(在這種情況下,2'Thread.sleep()')之間還有一段時間 - 你的解決方案只能真正阻止不管任務的狀態如何,兩行都被同時打印。我在想這個太過分了嗎?有更好的解決方案嗎? –

+0

沒有辦法阻止「工作完成」和「殺死計時器」之間的競爭,因爲Java沒有辦法說「當這段代碼完成時創建鎖定」。目標是編寫始終表現的代碼。定時器取消「殺死定時器」代碼時無關緊要。但是當計時器被取消兩次或類似的事情時,這可能是一個問題。 –

+0

那麼爲什麼還要在一個對象上同步呢?如果我們只能將競態條件僞裝成適當的同步,那麼讓外部對象/線程監視任務的狀態更合適嗎?該任務可以存儲一個布爾值來確定它是否被中斷,並且外部線程可以等待任務完成,然後根據布爾值打印正確的行。我不滿意你的迴應!必須有一個正確的方法:)編輯:你編輯你的評論添加「總是表現」的一部分,這是有道理的。我想沒有什麼可以「修復」。 –