我有以下程序有2个线程T1和T2。 T1首先运行并进入等待状态。 T2正在呼叫通知。为什么T1线程不会恢复并打印“Thread-0被唤醒”
public class WaitNotifyTest{
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " is running");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is waken up");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (this) {
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " is running");
notify();
System.out.println(Thread.currentThread().getName() + " notifying");
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
});
t1.start();
t2.start();
}
}
输出为
Thread-0 is running
Thread-1 is running
Thread-1 notifying
请注意,此输出后我的程序不会结束/终止。任何人都可以解释为什么我的程序没有终止。
答案 0 :(得分:2)
你的代码中有两个问题 1.您应该使用相同的对象在线程之间进行通信。 2.call等待并通知您已锁定的同一对象。
public class WaitNotifyTest{
public static void main(String[] args) {
Object lock=new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " is running");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is waken up");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " is running");
lock.notify();
System.out.println(Thread.currentThread().getName() + " notifying");
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
});
t1.start();
t2.start();
}
}
答案 1 :(得分:1)
我认为这是由于synchronized (this)
用于锁定目的。
在t1中,这将引用在那里创建的匿名类的Object。
在t2中,这将引用在那里创建的另一个匿名类的Object。简单来说,两者都指的是不同的对象。
对于wait-notify
工作,您必须锁定同一个对象。
答案 2 :(得分:1)
问题是您没有在同一个对象上进行同步。尝试在每个线程中打印this
进行验证。然后尝试在同一个对象上进行同步,在该锁定上调用wait
和notify
(否则您将无法获得正确的响应)。
public class WaitNotifyTest{
public static void main(String[] args) {
Integer someObject = 2;
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t1 this = " + this);
synchronized (someObject) {
System.out.println(Thread.currentThread().getName() + " is running");
try {
someObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is waken up");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t2 this = " + this);
synchronized (someObject) {
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " is running");
someObject.notify();
System.out.println(Thread.currentThread().getName() + " notifying");
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
});
t1.start();
t2.start();
}
}
答案 3 :(得分:1)
wait
和notify
。您必须在同一个对象上进行同步,以便线程能够等待 - 通知对方。
您可以在它们之间共享对象,并使用与监视器相同的共享wait
使用同步块调用notify
和Object
。以下解决了问题:
public static void main(String[] args) {
Object obj = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + " is running");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is waken up");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " is running");
obj.notify();
System.out.println(Thread.currentThread().getName() + " notifying");
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
});
t1.start();
t2.start();
}
请注意,synchronized (this)
现在为synchronized (obj)
,等待wait
和notify
不是obj.wait()
和obj.notify()
。
答案 4 :(得分:1)
我同意你在错误对象上同步的其他答案。
我建议"在监视器中思考"。监视器是限制并发访问以保留内部合作状态的对象。因此,监视器可以清楚地确保同步,并且不会在任何单个线程中遍布整个位置。线程不应该彼此同步,它们应该通过它们尝试访问的资源进行同步。
public class Main {
private static class Monitor {
public synchronized void operation1() {
System.out.println(Thread.currentThread().getName() + " is running");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is waken up");
}
public synchronized void operation2() {
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " is running");
notify();
System.out.println(Thread.currentThread().getName() + " notifying");
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
public static void main(String[] args) {
Monitor monitor = new Monitor();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
monitor.operation1();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
monitor.operation2();
}
});
t1.start();
t2.start();
}
}
答案 5 :(得分:1)
除了锁定不同对象的事实(由他人提及)之外,您的代码中还有另一个问题。你使用Thread.sleep
来确保等待线程在其他调用notify
之前开始等待,但你仍然没有猜测它不会发生反过来,使得等待线程永远等待。
你必须在while循环中使用一些'condition variable'才能安全起见。
阅读oracle's docs以获取示例和进一步说明。