2009-12-29 33 views
3

我試圖根據TimeUnit.timedWait(Object, long)實施Future.get(long, TimeUnit)如何在不失去納秒精度的情況下使用TimeUnit.timedWait()?

目前還不清楚如何使用TimeUnit.timedWait(Object, long)來處理虛假喚醒而不會丟失TimeUnit的納秒組件。通常你會這樣做:

public V get(long timeout, TimeUnit unit) 
{ 
    long expirationTime = new Date().getTime() + unit.toMillis(timeout); 
    while (!condition) 
    { 
    long timeLeft = expirationTime - new Date().getTime(); 
    if (timeLeft <= 0) 
     throw new TimeoutException(); 
    unit.timedWait(object, timeLeft); 
    } 
} 

但你失去了納秒組件。如果每個人都放棄納秒分量,那麼TimeUnit甚至可以支持納秒並提供TimeUnit.timedWait()

+0

你能澄清一下你擔心虛假喚醒的情況嗎?代碼中是否有某些東西使得很難清楚誰在控制對象Monitor? – 2009-12-29 17:00:41

+0

我很確定誰在控制對象Monitor。虛假喚醒指的是即使沒有人調用notify()或發生超時,wait()操作也可能返回。 – Gili 2009-12-29 20:08:19

回答

1

CountDownLatch似乎是實現這個最簡單的方法:

public class MutableFuture<T> implements Future<T> 
{ 
    private final CountDownLatch done = new CountDownLatch(1); 
    private T value; 
    private Throwable throwable; 

    public synchronized boolean isDone() 
    { 
    return done.getCount() == 0; 
    } 

    public synchronized T get(long timeout, TimeUnit unit) 
    throws InterruptedException, ExecutionException, TimeoutException 
    { 
    if (!done.await(timeout, unit)) 
     throw new TimeoutException(); 
    if (throwable != null) 
     throw new ExecutionException(throwable); 
    return value; 
    } 

    // remaining methods left as exercise to the reader :) 
} 

CountdownLatch不易受spurious wakeups(因爲它可以在返回之前在內部檢查鎖存狀態)。

3

在您等待之前,請存儲您想要超時的時間。

在通知等待線程之前,請設置一些共享(同步)狀態信號,表示由於計算完成,等待線程應該停止等待。

當你的線程從等待任何原因而被喚醒時,它應該檢查共享狀態,看它是否應該停止等待,並且它還應該檢查在超時到期之前還剩多久。如果超時沒有過期,並且共享狀態告訴沒有說停止等待,那麼你應該再次等待(但是使用從當前時間計算的新的較短超時)。

+1

目前還不清楚如何存儲你想要超時而不丟失TimeUnit的納秒組件的時間。如果每個人都簡單地放棄納秒組件,那麼TimeUnit甚至支持納秒並提供TimeUnit.timedWait()是什麼? – Gili 2009-12-29 20:17:23

+0

哇,好點的吉利。很深,但很好。 – LWoodyiii 2009-12-30 00:24:52

+0

嗯,我不能說他們爲什麼選擇允許納秒精度。在實踐中,我懷疑你會從普通的操作系統中獲得精確度。如果你確實需要這個精度,那麼使用垃圾收集語言聽起來像是一個非常糟糕的主意。 – 2009-12-30 02:34:00

1

的回答你的問題在於Object.wait(long)規格:

線程也可以醒不被通知,中斷或超時,所謂的虛假喚醒。雖然這在實踐中很少會發生,但應用程序必須通過測試應該引起線程被喚醒的條件來防範它,並且在條件不滿足時繼續等待。換句話說,等待應總是發生在循環中,像這樣的:

synchronized (obj) { 
    while (<condition does not hold>) 
     obj.wait(timeout); 
    ... // Perform action appropriate to condition 
} 

(有關此主題的更多信息,請參見3.2.3節在Doug Lea的「使用Java語言(第二版)並行編程」(艾迪生。-Wesley,2000),或第50條在約書亞布洛赫的 「有效的Java編程語言指南」(Addison-Wesley出版社,2001年)

+0

您需要記得在有些時間已經過去的情況下等待第二次減少超時。 – 2009-12-30 02:32:07

相關問題