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();
}
}
}
}
}
}
}
答案 0 :(得分:3)
您无法在i
上进行同步,因为它会在您执行程序时发生变化。
由于Java中的Integer
是不可变的,因此在执行i++
i
之后将包含对另一个对象的引用,而不是您synchronized
上的对象。因此,您无法在此新对象上调用wait()
/ notify()
,因为这些方法只能在您synchronized
上的对象上调用,否则您将获得IllegalMonitorStateException
您需要在执行期间不会更改的其他对象上进行同步。例如,您可以为此目的创建一个单独的对象:
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();
...
}
}
}
}
答案 1 :(得分:1)
这一行:
i++;
相当于:
i = i + 1;
(由于自动装箱)变成了类似的东西:
i = new Integer(i.intValue() + 1);
因此,当您致电i.notify()
时,您会在旧 i
上同步,而不是新的。
我建议将i
更改为普通的int
变量,并创建一个单独的对象进行同步:
static int i = 0;
static Object iMonitor = new Object();
答案 2 :(得分:0)
正如文档所述,
时会抛出异常当前线程不是对象监视器的所有者
它还说明了
此方法只应由作为此对象监视器所有者的线程调用。
这种情况可以通过
获得您可以尝试从使用i
的类中调用wait方法。这可以通过扩展课程并为notify
和wait
编写两个新方法来完成。
答案 3 :(得分:-1)
您不能将wait()和notify()放在同一个同步块中,因为这只会导致死锁。确保只有wait和notify函数包含一个synchronized块,如下所示:
synchronized (i) {
i.wait(); // or i.notify();
}