2013-10-18 49 views
1

我有這樣的代碼:的Java的Thread.join()方法凍結如果線程被整理

public void testThreads() throws Exception { 
    MyThreadManager mgr = createAndStartMyManager(); 
    Thread t1 = createMyThread(mgr, 1); 
    Thread t2 = createMyThread(mgr, 2); 

    t1.start(); 
    t2.start(); 

    //do some checks 

    t1.join(); 
    t2.join(); 
} 

MyThreadManager與線程操作,並且可以中斷任何人在任何時間。 由於這是測試用例的一部分,我需要調試正在運行的線程,我添加了joins以讓測試等待完成我的調試(JUnit在測試完成時斷開調試器)。

的問題是,在某些情況下,加入掛起 - jstack輸出是這樣的:

at java.lang.Object.wait(Native Method) 
    - waiting on <0xeec68eb0> (a java.lang.Thread) 
    at java.lang.Thread.join(Thread.java:1143) 
    - locked <0xeec68eb0> (a java.lang.Thread) 
    at java.lang.Thread.join(Thread.java:1196) 
    at MyClass.testThreads(MyClass.java:100) 

,並根據join JDK(我用1.6.0_07)的實施似乎線程完成只調用之間isAlivewait(標記爲源代碼):

public final synchronized void join(long millis) 
throws InterruptedException { 
    long base = System.currentTimeMillis(); 
    long now = 0; 

    if (millis < 0) { 
     throw new IllegalArgumentException("timeout value is negative"); 
    } 

    if (millis == 0) { 
     while (isAlive()) { 
      // -----> here ???? <------ 
      wait(0); 
     } 
    } else { 
     while (isAlive()) { 
      long delay = millis - now; 
      if (delay <= 0) { 
       break; 
      } 
      wait(delay); 
      now = System.currentTimeMillis() - base; 
     } 
    } 
} 

我試圖用的ThreadPoolExecutor和FutureTask相同,但行爲是一樣的(它是掛)。

所以我的問題是,如果我對比賽狀況的真實,以及如何清晰地加入線程沒有任何掛...

感謝

回答

2

所以我的問題是,如果我真的與競賽條件,以及如何清楚地連接線程沒有任何掛...

不,沒有在該方法的比賽。因爲方法是​​,競賽條件解決了。如果這是一個競爭條件,那麼在此之前大量的Java線程可能會失敗。我懷疑你加入的線程仍在運行。這不可能嗎?

的問題是,在某些情況下,加入掛起 - jstack輸出是這樣的:

這堆輸出表明,它在阻止join()。正如@Holger提到的,你能看到t1t2堆棧嗎?

Thread t1 = createMyThread(mgr, 1, "t1"); // name passed to thread constructor 
Thread t2 = createMyThread(mgr, 2, "t2"); // name passed to thread constructor 

MyThreadManager與線程操作,並且可能會中斷

你打電話thread.interrupt():這樣你就可以在堆棧跟蹤輸出更容易看到他們可能是來命名線程有用嗎?如果是這樣,這不會導致線程停止,除非您正在測試線程中斷位和/或正在正確處理InterruptedException

while (!Thread.currentThread().isInterrupted()) { 

你還需要,如果一個第三方庫沒有重新啓用中斷位,如果能抓住InterruptedException工作。正確的方式是做這樣的事情:

​​

我試圖用的ThreadPoolExecutor和FutureTask相同,但行爲是一樣的(它是掛)。

使用TPE時,您需要確保執行程序在所有作業都被提交後關閉。這會導致您的應用程序掛起,但不會顯示與在join()中阻止相同的行爲。

+2

任何投票回答的人都應該留下解釋原因的評論。一個解釋可以幫助答案的人被拒絕投票,而其他任何人都會在答案上發生。 – axiopisty

+1

好吧,我給你一個upvote。我只想給提問者添加一條評論:當使用'jstack'時,值得看看線程't1'和't2'在做什麼。但是其他一切都已經在這個答案中說過了。 – Holger

+0

這是一個很好的寫作。我認爲op的線程正在運行/阻塞在一個不可中斷/無中斷的代碼上。 Op應該在線程上調用'getStackTrace()'來看看他們在做什麼(或者使用jvisual VM或類似的)。 –