5

We use code that uses syncronized blocks around segments of code with a lot of wait and notifyAll() calls. We are trying to convert these to use Java 5 Lock.lock() and Lock.unlock() methods. How do I migrate this code to remove all the wait and notifyAll calls. I do not know the equivalent to these using the new Locking features.

Any links with examples would be appreciated.

Thanks in Advance

Eq., the following code needs to be converted to use Lock.lock() and lock.unlock The first part to remove the synchronized block is simple as I just need to call lock() method. The question is what can be done for the notifyAll() and wait methods.

     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;
                    }
                }
            }
4
  • If you could post a code sample, you'll get better results- there are many concurrency primitives in 1.5. Giving you advice outside of an example would be probably give you the wrong answer. Commented May 3, 2011 at 20:47
  • Thanks for your reply. I have added the code snippet you asked for. Commented May 3, 2011 at 21:26
  • 3
    ReentrantLocks are more error-prone than synchronized blocks - it is easy to miss the finally block. So unless you need some specific feature - lockInterruptibly or tryLock - there is no point in converting the code. If you are determined to migrate the code to newer APIs, you should consider restructuring the code to use higher-level APIs like Semaphores, Latches or Barriers. Commented May 3, 2011 at 22:46
  • @Binil - i agree with everything except your reference to Semaphore. i would consider a Semaphore to be the same "level" of API as Lock and wait/notify. Commented May 4, 2011 at 0:32

3 Answers 3

7

Use the Conditions provided by the java.util.concurrent.locks package:

 final Object monitor = ...

 ...

 synchronized (monitor) {

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

becomes:

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

 ...

 lock.lock();

 try {

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

 } finally {

     lock.unlock();
 }

The signalling side is pretty similar:

 synchronized (monitor) {

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

becomes:

 lock.lock();

 try {

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

 } finally {

     lock.unlock();
 }
Sign up to request clarification or add additional context in comments.

Comments

4

Use Condition objects provided by the Lock.newCondition() factory method. The waiting and notification aspects of an Object's monitor were factored out into this interface.

From a migration point of view:

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

However, conditions are more powerful than monitors in several ways. Firstly they are more fine grained, so you can have multiple conditions for different things. If I have a bounded blocking collection for instance, I can have a condition for full and a condition for empty, and await and notify these separately as elements are added or removed.

There are also additional await variants that allow you to await without being interrupted and await until a certain specific date (time).

The javadocs of the Condition class are very good and describe it and its use in great detail.

Comments

0

Since this question is talking about notifyAll, i have tried some example of producer/consumer with phaser. I didn't used Lock, since that needs try/finally, condition object, and till unlock other thread will not work... etc...

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.");
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.