I have created an java thread and passed an stack reference to it's constructor,
which initialize thread stack reference.
In run method i have created an synchronized block with that stack object,
the moment am calling wait in run inside synchronized block , i am getting IllegalMonitorStateException.
Thread Class :
public class Producer extends Thread {
Stack<String> stack=null;
public Producer(Stack<String> stack) {
this.stack=stack;
}
#Override
public void run() {
synchronized (stack) {
if(stack.isEmpty()){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Main Class:
public class MainClass {
public static void main(String[] args) {
Stack<String> stack=new Stack<String>();
Producer p=new Producer(stack);
p.start();
}
}
Output :
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at demo.Producer.run(Producer.java:20)
For wait() (or notify()) to work, you must call it on the same object. What you have now is the same as
synchronized (stack) {
if(stack.isEmpty()){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
instead you should do
synchronized (stack) {
if(stack.isEmpty()){
try {
stack.wait(); // wait on the same object synchronized.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Note: as wait can wake spuriously you have do this in a loop or your method could return prematurely.
synchronized (stack) {
while (stack.isEmpty()){
try {
stack.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Related
I was looking at a producer-consumer example with wait and notify, even though it works some times it gives exception. Not able to figure out where the problem is.
Exception in thread "Thread-5" java.util.NoSuchElementException at
java.util.LinkedList.removeFirst(Unknown Source) at com.bhatsac.workshop.producerconsumer.ProdNConsumer.consumer(ProdNConsumer.java:55)
at com.bhatsac.workshop.producerconsumer.ProdConsumerInvoker.lambda$5 (ProdConsumerInvoker.java:35)
at java.lang.Thread.run(Unknown Source)
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
public class ProdNConsumer {
LinkedList<Integer> list = new LinkedList<Integer>();
private int LIMIT = 1;
private volatile boolean shutdown = false;
private AtomicInteger counter=new AtomicInteger(0);
private Object lock=new Object();
public void produce() {
while (true) {
synchronized(lock){
System.out.println("In producer :)"+ list.size());
if(this.list.size()==this.LIMIT){
try {
System.out.println("In waiting state producer");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced by thread= "+ Thread.currentThread().getName());
list.add(counter.getAndIncrement());
System.out.println("Going to sleep for a while");
lock.notifyAll();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void consumer() {
while (true) {
synchronized(lock){
System.out.println("In consumer :)");
if(list.size()==0){
try {
System.out.println("In waiting state consumer");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("consumed by thread="+ Thread.currentThread().getName());
list.removeFirst();
lock.notifyAll();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ProdConsumerInvoker {
public static void main(String[] args) {
ProdNConsumer pc= new ProdNConsumer();
Thread tc1=new Thread(()->{pc.consumer();});
new Thread(()->{pc.produce();}).start();
new Thread(()->{pc.produce();}).start();
Thread tp1=new Thread(()->{pc.produce();});
new Thread(()->{pc.consumer();}).start();
new Thread(()->{pc.consumer();}).start();
tp1.start();
tc1.start();
}
}
Your producer and consumer threads are using the same lock. When a consumer wakes up and consumes an element, it calls lock.notifyAll(), which will wake up all consumers and producers waiting on it. Another consumer wakes up thinking there are items in the list, but it removes the first item from an empty list, causing the exception.
In the consumer, instead of if(list.size()==0), use while(list.size()==0). Similar reasoning applies to the producer as well. Just because the thread woke up doesn't mean that the condition it is waiting on is true. It only means that before the thread woke up the condition was true. It must check it again.
According to How to use wait and notify in Java? I have to synchronized on the same object to call notify.
I have synchronized on the same haveCoffee object. Why I am getting IllegalMonitorStateException when I call the notify method ?
I am Sleeping
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.example.concurrent.basic.WaitAndNotify$2.run(WaitAndNotify.java:42)
in the following code:
public class WaitAndNotify {
public static void main(String[] args) {
Thread haveCoffee = new Thread() {
public void run() {
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("I am awake and ready to have coffee");
}
}
};
Thread me = new Thread() {
public void run() {
synchronized (haveCoffee) {
try {
System.out.print("I am Sleeping");
Thread.sleep(4000);
notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
haveCoffee.start();
me.start();
}
}
On the first Thread, you call wait on an object while having its monitor (the object being this haveCoffee).
However, on the second thread, you call notify() on me, while having the monitor of haveCoffee.
This should work:
public class WaitAndNotify {
public static void main(String[] args) {
final Thread haveCoffee = new Thread() {
public void run() {
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("I am awake and ready to have coffee");
}
}
};
Thread me = new Thread() {
public void run() {
synchronized (haveCoffee) {
try {
System.out.print("I am Sleeping");
Thread.sleep(4000);
haveCoffee.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
haveCoffee.start();
me.start();
}
}
From oracle documentation page,
public class IllegalMonitorStateException
extends RuntimeException
Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.
Whenever you get this exception, just go through your code and check wait() and notify() calls and the object on which these calls have been invoked. You can easily figure out what went wrong.
EDIT:
wait() or notify() calls have to be invoked on object once you get monitor on that object.
You should be calling
haveCoffee.notify()
instead of just
notify().
If you invoke just notify() it calls the notify() method on the this object which is the second thread me where as you have synchronized on haveCoffee thread and that is the reason for exception you are seeing.
So the code in thread2 me should looks like:
synchronized (haveCoffee) {
try {
System.out.print("I am Sleeping");
Thread.sleep(4000);
haveCoffee.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I am trying to do it using two threads like below. Can someone point the obvious mistake I am doing here?
public class OddEven {
public static boolean available = false;
public static Queue<Integer> queue = new LinkedList<Integer>();
static Thread threadEven = new Thread() {
#Override
public void run() {
printEven();
}
public synchronized void printEven() {
while (!available) {
try {
wait();
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println(queue.remove());
available = false;
notifyAll();
}
};
static Thread threadOdd = new Thread() {
#Override
public void run() {
printOdd();
}
public synchronized void printOdd () {
while (available) {
try {
wait();
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println(queue.remove());
available = true;
notifyAll();
}
};
public static void main(String[] args) {
int n = 20;
for (int i = 1; i < n; i++) {
queue.add(i);
}
threadOdd.start();
threadEven.start();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
threadOdd.join();
threadEven.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
But this program is only printing 1 and quitting. After printing 1 the available should be true and printEven should wake up, print and set available to false. I don't understand what is going wrong here? I saw other solutions but want to know why my solution is not working.
Putting synchronized on an instance method means that the thread calling that method has to acquire the lock on that instance; public void synchronized printOdd() is syntax sugar for
public void printOdd() {
synchronized(this) {
...
}
}
where this is different for each instance, since ThreadOdd and threadEven are two different objects and each one uses its own lock. The methods notifyAll and wait are called on the object that is being used as the lock. When one thread waits it never gets notified because the notification only applies to other threads waiting on the same lock as the notifying thread.
class myThreadRun implements Runnable
{
public void run() {
roo();
}
public synchronized void roo()
{
System.out.println("In thread before wait " + Thread.currentThread().getName());
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JOptionPane.showMessageDialog(null, "After wait in\n"+Thread.currentThread().getName());
System.out.println("In thread after wait " + Thread.currentThread().getName());
//notify();
}
public synchronized void foo()
{
notify();
}
}
public class ThreadingDemo {
public synchronized void Start()
{
System.out.println("Labamba");
myThreadRun mThRun = new myThreadRun();
Thread thread = new Thread(mThRun);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//mThRun.foo(); //This works
//mThRun.notify(); //crash
//thread.notify();//crash
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
new ThreadingDemo().Start();
}
This is simple code to demonstrate wait() and notify(),
In the myThreadRun class run() method just does wait() and foo() method does notify()
as indicated in the code above, if I do mThRun.notify() the program crashes, but mThRun.foo() runs the without a hitch and gives the much needed result. I need to know why?
You need to own the monitor for the object to all obj.wait() and obj.notify().
That is why it works when called within the synchronized block on mThRun but not outside. So if you put the mThRun.notify(); in a synchronized block, it works, like this:
synchronized (mThRun) {
mThRun.notify();
}
In your case you are getting an IllegalMonitorStateException.
Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.
Put another way, you don't hold the lock of the object you are trying to notify. Having the lock of a different object doesn't help.
When you use notify() and wait() you need to change a state and check for it. If you don't do this, you can find that either
notify() is called before wait() and the signal is lost
wait() wakes prematurely
You cannot assume notify/wait is a reliable messaging protocol.
I suggest you consider using the concurrency library which is a better choice in most cases from Java 5.0 (2004)
May be you are going very hard with wait/notify. Its very simple. what you need to know is which object is used for monitor lock. To make the same code working i have modified the same code: ( I have put MAK comment where i changed the code, hope its helpful)
class MyThreadRun implements Runnable {
public void run() {
roo();
}
public synchronized void roo() {
System.out.println("In thread before wait " + this);
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
JOptionPane.showMessageDialog(null, "After wait in\n" + Thread.currentThread().getName());
System.out.println("In thread after wait " + Thread.currentThread().getName());
}
}
public class ThreadingDemo {
public static void main(String[] args) {
MyThreadRun mThRun = new MyThreadRun();
System.out.println("Labamba: " +mThRun);
Thread thread = new Thread(mThRun);
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
//mThRun.foo(); //This works //MAK: no sense
//mThRun.notify(); //crash //MAK: Need monitor lock
synchronized (mThRun) {
mThRun.notify();//crash //MAK: will work now
}
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
try {
thread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end");
}
this sentence will throw :
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
but use "thread.join()" to replace "thread.wait(0)' doesn't throw any exception.
The puzzle is
I query the thread.join() source code: it will go to :
while(isAlive)
wait(0);
it means they both trigger wait(0). but why the result is so different?
Take another look at the source code and you will find the join is done while holding the monitor ( while synchronized ). If you want to use "thread.wait(0)" you need to wrap it in a synchronized block or method.
Have a look at: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
Object o = new Object();
synchronized (o) {
o.wait(timeInMS);
}
and so in your code try
synchronized (thread) {
thread.wait(0);
}