Java 通知后等待线程没有恢复
Java waiting Thread doesn't resume after notify
我下面的程序有 2 个线程 T1 和 T2。 T1先是运行,进入waiting状态。 T2 正在调用通知。为什么 T1 线程不恢复并打印 "Thread-0 is waken up"
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
注意在这个输出之后我的程序没有 ends/terminate。谁能解释一下为什么我的程序没有终止。
我认为这是因为 synchronized (this)
被用于锁定目的。
在 t1 中,这将引用在那里创建的匿名 class 的对象。
在 t2 中,这将引用在那里创建的另一个匿名 class 的对象。简单来说,两者所指的对象不同。
为了wait-notify
工作,您必须锁定同一对象。
问题是您没有在同一个对象上进行同步。尝试在每个线程中打印 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();
}
}
您没有正确使用 wait
和 notify
。
您必须在同一个对象上进行同步,以便线程能够相互等待通知。
您可以在它们之间共享一个对象,并使用与监视器相同的共享 Object
使用同步块调用 wait
和 notify
。以下解决了问题:
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()
。
您的代码中存在两个问题
1.You 应该使用相同的对象在线程之间进行通信。
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();
}
}
我同意您同步错误对象的其他答案。
我建议"think in monitors"。监视器是限制并发访问以保持内部一致状态的对象。因此,同步显然是由监视器确保的,并且不会在任何单个线程中遍布整个地方。线程不应相互同步,它们应该由它们尝试访问的资源同步。
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();
}
}
除了您锁定不同对象这一事实(其他人提到)之外,您的代码中还有另一个问题。您使用 Thread.sleep
来确保等待线程在其他调用 notify
之前开始等待,但您仍然没有保证它不会以相反的方式发生,从而使等待线程永远等待。
为了安全起见,您还必须在 while 循环中使用一些 'condition variable'。
阅读 oracle's docs 以获取示例和进一步说明。
我下面的程序有 2 个线程 T1 和 T2。 T1先是运行,进入waiting状态。 T2 正在调用通知。为什么 T1 线程不恢复并打印 "Thread-0 is waken up"
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
注意在这个输出之后我的程序没有 ends/terminate。谁能解释一下为什么我的程序没有终止。
我认为这是因为 synchronized (this)
被用于锁定目的。
在 t1 中,这将引用在那里创建的匿名 class 的对象。
在 t2 中,这将引用在那里创建的另一个匿名 class 的对象。简单来说,两者所指的对象不同。
为了wait-notify
工作,您必须锁定同一对象。
问题是您没有在同一个对象上进行同步。尝试在每个线程中打印 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();
}
}
您没有正确使用 wait
和 notify
。
您必须在同一个对象上进行同步,以便线程能够相互等待通知。
您可以在它们之间共享一个对象,并使用与监视器相同的共享 Object
使用同步块调用 wait
和 notify
。以下解决了问题:
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()
。
您的代码中存在两个问题 1.You 应该使用相同的对象在线程之间进行通信。 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();
}
}
我同意您同步错误对象的其他答案。
我建议"think in monitors"。监视器是限制并发访问以保持内部一致状态的对象。因此,同步显然是由监视器确保的,并且不会在任何单个线程中遍布整个地方。线程不应相互同步,它们应该由它们尝试访问的资源同步。
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();
}
}
除了您锁定不同对象这一事实(其他人提到)之外,您的代码中还有另一个问题。您使用 Thread.sleep
来确保等待线程在其他调用 notify
之前开始等待,但您仍然没有保证它不会以相反的方式发生,从而使等待线程永远等待。
为了安全起见,您还必须在 while 循环中使用一些 'condition variable'。
阅读 oracle's docs 以获取示例和进一步说明。