2

I have created a producer consumer program using threads (wait and notify) feature. The code is -

/**
 *  Message.java ( Common object )
 */
package threads;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author chouhan_r
 *
 */
public class Message {
    private String message;

    ReentrantLock lock = new ReentrantLock();
    ReentrantLock takelock = new ReentrantLock();
    private boolean empty =true;
    public  void put(String message){
        lock.lock();
        while(!empty){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        empty = false;
        this.message = message;

        notifyAll();
        lock.unlock();
    }

    public String take(){

        takelock.lock();
        while(empty){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        empty = true;

        notifyAll();
        takelock.unlock();
        return message;

    }


}


/**
 * Producer.java
 */
package threads;

import java.util.Random;

public class Producer implements Runnable{
    private Message message;
    public Producer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        String[] impInfo = {"Hello", "I am here", "why are you doing this ??", "No problem" };
        Random random = new Random();
        for(String str : impInfo){
            message.put(str);
            try {
                Thread.sleep(random.nextInt(3000));
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        message.put("Finished");

    }



}

/**
 * Consumer.java
 */
package threads;

public class Consumer implements Runnable{
    private Message message;
    public Consumer(Message message) {
        this.message = message;
    }
    @Override
    public void run() {
        System.out.println(message);
        String msg = message.take();
        while(!"Finished".equalsIgnoreCase(msg)){
            System.out.println(msg);
            msg = message.take();
        }


    }


}

=====================

/**
 * Main Program
 */
package threads;

public class ProConsTest {

    public static void main(String[] args) {
        Message message = new Message();
        new Thread(new Consumer(message)).start();
        new Thread(new Producer(message)).start();



    }

}

I am trying to execute this code using ReentrantLock but it is giving me followin error -

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at threads.Message.take(Message.java:39)
    at threads.Consumer.run(Consumer.java:11)
    at java.lang.Thread.run(Unknown Source)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)
    at threads.Message.put(Message.java:31)
    at threads.Producer.run(Producer.java:16)
    at java.lang.Thread.run(Unknown Source)

Am I doing something wrong here ?? when I mark methods in Message.java as synchronized it works perfect. Can we run this code only with the Reentrant lock ??

Holger
  • 285,553
  • 42
  • 434
  • 765
Rakesh Chouhan
  • 1,196
  • 12
  • 28
  • That's because `wait()` and `notify()` require you to own the object monitor, i.e. synchronize on whatever you're calling them on. – Kayaman May 07 '15 at 13:57
  • @Kayaman Can it be done with Reentrant lock ?? – Rakesh Chouhan May 07 '15 at 14:01
  • I read in a blog that " ReentrantLock provides same visibility and orderings guaranteed as implicit lock, acquired by synchronized keyword in Java" So I am trying do this without Synchronized method or any Synchronized block. Is it possible ?? – Rakesh Chouhan May 07 '15 at 14:06
  • It is not duplicate question @Kayaman, here I dont want to use the synchronize block or synchronize method, I want to run this using locks. – Rakesh Chouhan May 07 '15 at 14:16

1 Answers1

4

Object.wait and Object.notify are connected to the intrinsic locking feature, which is used with synchronized blocks and methods.

If you want to use Locks, you can’t use these two methods. Instead you have to create a Condition and call await() on it, which should be paired with another thread calling signal() on the same Condition instance. Note that unlike Object.wait and Object.notify, you can have more than one Condition per Lock and threads waiting for a particular condition will be woken up by threads calling signal on the same Condition instance.

However, as with the intrinsic locking feature, you must own the associated lock before calling a method on a Condition. In case of a ReadWriteLock, you must own the write lock.

Unfortunately, Conditions inherit the methods wait and notify from Object, so it’s important to never mix them up, which requires special care due to the hard to distinguish names, wait and await.

The documentation of Condition contains a complete example. I just pick up one code fragment illustrating the usage in the put method:

final Lock lock = new ReentrantLock();
final Condition notFull  = lock.newCondition(); 
final Condition notEmpty = lock.newCondition(); 

lock.lock();
try {
  while (count == items.length)
    notFull.await();
  items[putptr] = x;
  if (++putptr == items.length) putptr = 0;
  ++count;
  notEmpty.signal();
} finally {
  lock.unlock();
}
Holger
  • 285,553
  • 42
  • 434
  • 765