public class ThreadTest
{
public static Integer i = new Integer(0);
public static void main(String[] args) throws InterruptedException
{
ThreadTest threadTest = new ThreadTest();
Runnable odd = threadTest.new Numbers(1, "thread1");
Runnable even = threadTest.new Numbers(0, "thread2");
((Thread) odd).start();
((Thread) even).start();
}
class Numbers extends Thread
{
int reminder;
String threadName;
Numbers(int reminder, String threadName)
{
this.reminder = reminder;
this.threadName = threadName;
}
@Override
public void run()
{
while (i < 20)
{
synchronized (i)
{
if (i % 2 == reminder)
{
System.out.println(threadName + " : " + i);
i++;
i.notify();
}
else
{
try
{
i.wait();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
views:
52answers:
4You cannot put wait() and notify() in the same synchronized block because that will just cause a deadlock. Make sure only the wait and notify functions are wrapped with a synchronized block like this:
synchronized (i) {
i.wait(); // or i.notify();
}
As documentation states the exception is thrown when
the current thread is not the owner of the object's monitor
It also states that
This method should only be called by a thread that is the owner of this object's monitor.
And this condition can be obtained by
- By executing a synchronized instance method of that object.
- By executing the body of a synchronized statement that synchronizes on the object.
- For objects of type Class, by executing a synchronized static method of that class.
You could try calling the wait method from inside the class that uses i
. This could be done by extending the class and writing two new methods for notify
and wait
..
You can't synchronize on i
because it changes during execution of your program.
Since Integer
in Java is immutable, after executing i++
i
will contain a reference to another object, not the object you have synchronized
on. So, you can't call wait()
/notify()
on this new object, because these methods may be only called on the object you are synchronized
on, otherwise you get IllegalMonitorStateException
.
You need to synchronize on some other object that doesn't change during execution. For example, you may create a separate object for this purpose:
public class ThreadTest {
public static Integer i = new Integer(0);
public static Object lock = new Object();
...
class Numbers extends Thread {
...
@Override
public void run() {
...
synchronized (lock) {
...
lock.notify();
...
lock.wait();
...
}
}
}
}
This line:
i++;
is equivalent to:
i = i + 1;
which (due to autoboxing) becomes something like:
i = new Integer(i.intValue() + 1);
So, when you call i.notify()
you are synchronized on the old i
, not the new one.
I'd suggest changing i
into an ordinary int
variable, and create a separate object to synchronize on:
static int i = 0;
static Object iMonitor = new Object();