2011-05-03 45 views
5

我們使用的代碼在代碼片段周圍使用syncronized塊,並使用大量wait和notifyAll()調用。我們試圖將這些轉換爲使用Java 5 Lock.lock()和Lock.unlock()方法。如何遷移此代碼以刪除所有wait和notifyAll調用。我不知道這些使用新的鎖定功能的等同物。轉換wait&notifyAll代碼以使用Java 1.5 Lock對象

任何與例子的鏈接將不勝感激。

由於提前

當量,需要下面的代碼被轉換爲使用Lock.lock()和lock.unlock第一部分以除去同步塊是簡單,因爲我只需要調用鎖( ) 方法。問題是可以爲notifyAll()和wait方法做些什麼。

 
    synchronized(LOCK) 
      { 
       while(!Thread.interrupted()) 
       { 
       try 
        { 

         working = runRules(); 

         if(!working) 
          LOCK.notifyAll(); 

         LOCK.wait(working ? shortTimeout : longTimeout); 
        } 
        catch(final InterruptedException e) 
        { 
         Package.log.info("Thread was interrupted. Exiting.", e); 
         return; 
        } 
       } 
      } 
+0

如果你可以發佈代碼示例,你會得到更好的結果 - 在1.5中有很多併發基元。在例子之外給你的建議可能會給你錯誤的答案。 – 2011-05-03 20:47:16

+0

感謝您的回覆。我已添加您要求的代碼段。 – Nadeem 2011-05-03 21:26:27

+3

'ReentrantLock'比'synchronized'塊更容易出錯 - 很容易錯過'finally'塊。所以,除非你需要一些特殊的功能 - lockInterruptibly或tryLock - 否則轉換代碼沒有意義。如果您決定將代碼遷移到更新的API中,則應考慮重構代碼以使用更高級別的API,如信號量,鎖存器或障礙。 – 2011-05-03 22:46:40

回答

7

使用Conditions provided by the java.util.concurrent.locks package

final Object monitor = ... 

... 

synchronized (monitor) { 

    while (!condition) monitor.wait(); 
    ... do something ... 
} 

變爲:

final ReentrantLock lock = ...; 
final Condition cvar = lock.newCondition(); 

... 

lock.lock(); 

try { 

    while (!condition) cvar.await(); 
    ... do something ... 

} finally { 

    lock.unlock(); 
} 

信令側是非常相似:

synchronized (monitor) { 

     ... do something ... 
     monitor.notify(); 
} 

變爲:

Lock.newCondition()工廠方法提供個
lock.lock(); 

try { 

    ... do something ... 
    cvar.signalAll(); 

} finally { 

    lock.unlock(); 
} 
+0

感謝您的回覆。我會試試這個 – Nadeem 2011-05-03 21:26:56

4

使用Condition對象。對象監視器的等待和通知方面被分解到這個接口中。

從一個遷移點:

  • wait() - >await()
  • wait(long) - >await(long, TimeUnit.Millis)awaitNanos(long * 10000000)
  • notify() - >signal()
  • notifyAll() - >signalAll()

但是,條件比監視器在幾個方面更強大。首先它們更加細膩,因此對於不同的事物可以有多種條件。如果我有一個有限的阻塞集合的例子,我可以有一個滿的條件和一個空的條件,並等待和分別通知這些元素添加或刪除。

還有另外的await變種,允許您等待而不被打斷並等待某個特定的日期(時間)。

Condition類的javadocs非常好,並且非常詳細地描述它以及它的使用。

+0

感謝您的回覆。 – Nadeem 2011-05-05 15:26:25

0

由於這個問題是在談論notifyAll,我已經嘗試了一些使用相位器的生產者/消費者的例子。我沒有使用鎖,因爲它需要嘗試/最後,條件對象,直到解鎖其他線程不會工作...等等...

import java.util.concurrent.Phaser; 

public class ProducerConsumerExample { 

    Phaser producer; 
    Phaser consumers; 
    volatile String array[]; 

    public void init() { 
     producer = new Phaser(5); 
     consumers = new Phaser(5); 
     Consumer l1 = new Consumer("Consumer_1"); 
     l1.setDaemon(true); 
     l1.start(); 
     Consumer l2 = new Consumer("Consumer_2"); 
     l2.setDaemon(true); 
     l2.start(); 
     Consumer l3 = new Consumer("Consumer_3"); 
     l3.setDaemon(true); 
     l3.start(); 
     Consumer l4 = new Consumer("Consumer_4"); 
     l4.setDaemon(true); 
     l4.start(); 
    } 

    class Consumer extends Thread { 

     Consumer(String name) { 
      super(name); 
     } 

     private void printMethod(String i) { 
      System.out.println(Thread.currentThread().getName() + " " + i); 
     } 

     public void run() { 
      while (true) { 
       //make the consumers sleep till producer produces 
       consumers.arriveAndAwaitAdvance(); 
       for (int i = 0; i < array.length; i++) { 
        printMethod(array[i]); 
       } 
       //alert the producer to start 
       producer.arriveAndAwaitAdvance(); 
       System.out.println(Thread.currentThread().getName() + " thread wakeup but will stuck with consumers.arriveAndAwaitAdvance!"); 

      } 
     } 
    } 

    public void run() { 
     for (int j = 0; j < 3; j++) { 
      array = new String[5]; 
      for (int i = 0; i < array.length; i++) { 
       array[i] = "Phase_" + (j + 1) + " Count_" + (i + 1); 
      } 
      System.out.println("Main thread pushed data."); 
      //alert the consumers to start 
      consumers.arriveAndAwaitAdvance(); 

      //make the producer sleep till all the consumer consumes 
      producer.arriveAndAwaitAdvance(); 
      System.out.println("Main thread wakeup and will start pushing data..."); 

     } 
    } 

    public static void main(String[] args) { 
     ProducerConsumerExample sch = new ProducerConsumerExample(); 
     sch.init(); 
     sch.run(); 
     System.out.println("Main thread completed, producing data."); 
    } 
}