2012-07-16 61 views
26

我知道Thread.sleep()方法可以使Java線程暫停了一段時間,如某些毫秒和某些納秒。但問題是這個函數的調用也會導致開銷。如何在一段很短的時間內暫停Java線程,例如100納秒?

例如,如果我想要一個線程暫停100納秒,並且我撥打Thread.sleep(0,100)。這個過程的整個成本是invocation_cost + 100 nanosceonds,這可能是我想要的更大。我怎麼能避免這個問題,並達到我的目的?

我需要這個的原因是我想離線模擬。我分析了任務的執行時間;現在我想通過在同一時間段內掛起一個線程來模擬這個執行時間。

謝謝!

+8

你有特別的理由說明你爲什麼要這樣做?如果是這樣,它可能以不同的方式解決... – 2012-07-16 05:39:00

+0

這是一個不尋常的要求。這聽起來像你需要[退出策略](http://en.wikipedia.org/wiki/Exponential_backoff)或類似的。 – Bohemian 2012-07-16 05:50:40

+1

@ FY FYI,這是煩人的發佈問題在計算器上,並有回答質疑你,而不是提供一個答案。想要這麼做的原因有很多,多年來已經出現在項目中。一個實際的原因是在硬件記錄音頻的應用程序中保持實時行爲,因爲硬件可能表現不一致,或者您可能爲了測試目的而模擬硬件行爲。 – EntangledLoops 2015-10-22 14:50:09

回答

17

睡覺的粒度通常通過線程調度的中斷週期的約束。在Linux中,這個中斷週期在最近的內核中通常爲1ms。在Windows中,調度程序的中斷期限一般在10或15毫秒

如果我不得不停止線程時間少於這個,我通常使用一個忙等待

編輯:我懷疑你會得到jrockit + solaris上的最佳結果。窗戶上的數字是可怕的。

@Test 
public void testWait(){ 
    final long INTERVAL = 100; 
    long start = System.nanoTime(); 
    long end=0; 
    do{ 
     end = System.nanoTime(); 
    }while(start + INTERVAL >= end); 
    System.out.println(end - start); 
} 
+1

謝謝。如果使用繁忙的等待,您如何控制等待時間?如100納秒。 – JackWM 2012-07-16 05:46:02

+1

**> = **是** <= **? – JackWM 2012-07-16 17:45:48

+0

對不起,我錯了 – JackWM 2012-07-16 17:46:49

1

Thread.sleep()還有一個問題是它不保證在指定的時間後喚醒。睡眠線程保證在指定的納秒/微秒內睡眠,但不保證在此之後立即喚醒。由於您正在談論納秒級的interms,因此您可能需要嘗試Object.wait(long, int)

我去過用上述方法納秒10s的順序相當一致。

+2

在這兩種情況下,當你調用Thread.sleep()和Object.wait()時,當前正在運行的線程進入TIMED_WAITING模式。這意味着線程放棄CPU。在這兩種情況下,當等待時間結束時,CPU很可能會忙於做其他事情。不能保證喚醒線程一次會收到CPU,即使這樣做,它仍然需要支付上下文切換時間,根據問題,這是查詢者想要避免的。 – 2012-07-16 12:37:23

+0

此外,在'Object.wait(timeout,nanos)'的代碼中,你可以看到如果'nanos> 0'只會將'timeout'增加1。 – awfun 2017-06-08 08:58:35

1

做一個忙等待(即經歷了那麼多的數字無爲有一個while循環週期)。一個程序的開始,你可以花費它執行這個繁忙的等待,並增加或減少它達到5納秒的時間量的時間量

我發現object.wait變得毛茸茸的這個頻率還注意到忙等待的解決方案將最有可能是機器相關的。因此,你爲什麼要在你的程序

12

對於模擬我不會試圖在實時模擬,因爲這不會給你重複的結果開始校準步驟。即你不能測試你的模擬。

相反,我會用驅動的數據,模擬時鐘,並儘可能快地運行一切。這使您可重複的結果,並允許您模擬快於實時(例如2倍至100倍速度)


懷疑一個線程需要大約10微秒。沒有意義的嘗試暫停一個線程更少的時間,這一點。

要想在短時間內忙着等待,可以試試。

long start = System.nanotime(); 
while(start + delay >= System.nanoTime()); 

注:爲@EugeneBeresovsky的意見,你的機器已經運行了292年這可能溢出等你以後可能會選擇寫爲

while(System.nanoTime() - start < delay); 

這將罰款小於292的延遲年代替。您可以使用System.currentTimeMillis()來延長更長時間。

但是,即使這樣也不可靠,因爲System.nanoTime()在CentOS 5.x上可能需要長達300 ns,所以調用它兩次將花費比100 ns更長的時間。此外,許多操作系統的分辨率只有1000納秒(1微秒),所以無論您尋找什麼延遲,該環路都會等待1微秒。

相反,你可以做的是忙於等待一個短的循環,這是沒有優化的方式。

對於100 ns的延遲,我懷疑最好是忙於等待你正在等待的任何東西,而不是創建一個單獨的忙碌循環。

+0

好帖子。我編輯< to > =糾正代碼(回想起來,「>」更好)。我做了一些其他微小的更改,以達到6(argh)的最小字符編輯。謝謝。 – 2013-12-30 16:11:29

+0

你的條件受到整數溢出錯誤的影響。您必須比較兩個nanoTime()結果與一些絕對值的差異,例如完成。通過@EntangledLoops,而不是比較兩個絕對nanoTime值彼此。 – 2016-06-30 05:06:27

+0

@EugeneBeresovsky在您的機器運行了292年之後,長期價值將會溢出......我將更新我的答案。 – 2016-07-01 08:24:14

2
public static void busySleep(long nanos) 
{ 
    long elapsed; 
    final long startTime = System.nanoTime(); 
    do { 
    elapsed = System.nanoTime() - startTime; 
    } while (elapsed < nanos); 
}