2011-05-03 52 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."); 
    } 
}