2016-09-24 107 views
0

我有4個線程同時填充一個50000000x4矩陣。爲了確保寫入安全,我使用了一個AtomicInteger作爲指針。每個迭代每個線程將指針值複製到threadPointer並使用它填充。 獲得指針== buffer.length的第一個線程啓動一個例程以將緩衝區刷新到內存中。此時的其他線程應等待線程完成其工作。 這是我的代碼:在java中喚醒等待線程

if ((threadPointer = pointer.getAndAdd(1)) >= buffer.length){ 
    synchronized (flag){ 
     if(threadPointer == buffer.length){ 
      sampledSelection(); 
      pointer.set(0); 
      threadPointer = pointer.getAndAdd(1); 
      flag.notifyAll(); 
     }else{ 
      System.out.println("waiting"); 
      flag.wait(); 
      threadPointer = pointer.getAndAdd(1); 
      System.out.println("Awaken!"); 
     } 
    } 
} 

我的問題是notifyAll()不會喚醒等待我threads.How可以解決這一問題?

+2

您的'wait'調用沒有使用[guarded blocks](https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)。這允許競爭條件,即如果一個線程將要到達'wait'調用但還沒有,另一個線程過早地調用'notifyAll',導致它永遠等待。 –

+0

我明白了。我發現我的代碼有一個導致意外行爲的錯誤。其中之一導致線程調用notifyAll(),然後我期望導致你寫的內容。謝謝。 – Aalto

回答

1

這聽起來像你想通了,但爲後人...

我的問題是,notifyAll的不會喚醒等待的線程。我怎樣才能解決這個問題?

對,你在這裏有一個典型的競賽條件。假設有3個線程在同一時間進行並執行pointer.getAndAdd(1)

  1. 線程#1首先調用synchronized (flag)並進入保護區域。
  2. 線程#2和#3調用synchronized (flag),但它們被鎖定,直到線程#1解鎖。
  3. 線程#1的pointer值等於緩衝區長度,所以它調用sampledSelection();,將pointer重置爲0,調用notifyAll(),然後解鎖。
  4. 線程#2(比方說)現在進入​​部分。這是pointer值不相等,所以它解鎖wait()
  5. 線程#3現在進入​​部分。這是pointer值不相等,所以它解鎖wait()

如果沒有人回來呼叫notifyAll()那麼他們將永遠等待。

正如你所想的那樣,重要的是要認識到notifyAll()方法的唯一工作方式是如果線程已經在等待。通常應該發生的是線程應該查看條件字段以查看是否應該等待。

另一件需要注意的事情是要確保你的對象​​是一個常數。你的情況應該flag等來定義:

private final Object flag = new Object(); 

如果您flag可以被分配到另一個值,那麼線程將不是同一個對象,這將導致問題上鎖定(或信號化)。務必確保您鎖定了一個final對象。

希望這會有所幫助。