我想做一个小练习来习惯等待/通知。我想做的是简单地启动一个线程,然后用等待让它进入睡眠状态,用通知唤醒它,多次。
我的代码是:
public class Simple{
static final Thread mainThread = Thread.currentThread();
public static void main(String[] args) throws InterruptedException {
PrintThread printer = new PrintThread(0);
printer.start();
synchronized (mainThread){
System.out.println("main sleeping while waiting for printer to be started");
mainThread.wait();
System.out.println("main woke up");
for (int i = 0; i < 1000; i++) {
synchronized (printer){
System.out.println("added num "+i);
printer.numToPrint = i;
System.out.println("main waking up printer");
printer.notifyAll();
System.out.println("main sleeping");
mainThread.wait();
System.out.println("main woke up");
}
}
}
}
}
class PrintThread extends Thread{
public int numToPrint = -1;
public PrintThread(int numToPrint){
this.numToPrint = numToPrint;
}
@Override
public synchronized void run() {
System.out.println("printer started");
while (true){
try {
synchronized (Simple.mainThread){
System.out.println("printer waking up main");
Simple.mainThread.notifyAll();
}
System.out.println("printer sleeping");
wait();
System.out.println("printer woke up");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("printing num "+numToPrint);
}
}
}
我希望这会是这样
main sleeping while waiting for printer to be started
printer started
printer waking up main
printer sleeping
main woke up
added num 0
main waking up printer
main sleeping
printer woke up
printing num 0
printer waking up main
printer sleeping
main woke up
added num 1
...
相反,这样做:
main sleeping while waiting for printer to be started
printer started
printer waking up main
printer sleeping
main woke up
added num 0
main waking up printer
main sleeping
所以。。。通知似乎没有唤醒打印机线程?
这不应该是一个死锁,因为通过等待,我释放了所有的锁,所以主服务器不应该有任何对打印机的锁,打印机应该能够唤醒并打印。
我做错了什么?
属性:调用等待()释放锁(它正在监控的锁)并进入等待状态。它在同一对象上等待通知()或通知所有()。一旦通知()或通知所有()并在CPU中进行调度,它就会在恢复之前再次获取锁。
当你第一次在main方法中“同步(mainThread)”时,它基本上锁定了“mainThread”类对象。当调用 mainThread.wait() 时,mainThread 进入等待状态(等待某人在 mainThread 类对象上调用 notify 或 notifyAll)。
此时,PrintThread可能会占用CPU。这是当“synchronized(Simple.mainThread)”被调度并锁定“Simple.minThread”并通知所有等待“Simple.mainThread”的线程时。在这个块完成后,PrintThread释放“Simple.mainThread”锁。
此时,主线程将再次尝试获取“主线程”上的锁,然后从调用等待的位置恢复。由于此时未获取“mainThread”锁,所以主线程获取锁并打印“main waked up”。
现在,这里遇到了for循环。记住:这里已经获取了“mainThread”类Object的锁。
现在在for循环内部,它获取“打印机”对象的锁。做一些计算,调用“printer.notify所有()”,所有等待“打印机”对象的线程都将被通知。
**这里要记住的一点是:由于代码光标仍在“同步(打印机)”内,因此“打印机”对象的锁定尚未释放。**
继续前进,打印“main sleeping”,然后调用“mainThread.wait()”。这尝试在已经获取的“mainThread”上获取锁(上面提到“记住:”在块中)并卡住,因为此后没有线程在“mainThread”上通知,并且“同步(打印机)”块永远不会结束,即即使在调用 NotifyAll() 之后,“打印机”对象的锁定也永远不会释放。
尝试在开始时的 Main 方法中添加以下代码,以测试上述场景。
synchronized (mainThread) {
synchronized (printer){
System.out.println("Before");
mainThread.wait();
System.out.println("After");
}
解决方案:关闭“printer.notifyAll()”之后的“synchronized(printer)”块,以便在通知之后和获取“mainThread”之前释放“printer”锁。
很可能您的 notifyAll() 调用是在打印调用 wait() 再次之前调用的。问题在于您依赖于等待和通知所有调用都按照您希望的顺序发生。这是两个不同的执行线程,所以当然不能保证这一点,因此你得到了你所拥有的。
实现此目的的更好方法是创建一个公共的第三个共享对象,两个线程都可以获取锁定。这将在两个线程等待访问此对象时同步它们。
另外,您应该阅读 Javadocs for Thread.wait、notify和 notifyAll。如果你这样做了,你会发现你永远不应该在线程上调用这些方法,因为它们用于执行thread.join(不仅如此,我的“名声”是我相信这是我多年前的错误请求,当这不在JavaDoc中时,导致它被添加到Javadoc中。可能是其他人,但它发生在我要求之后:))
本文向大家介绍Java多线程基础 线程的等待与唤醒(wait、notify、notifyAll),包括了Java多线程基础 线程的等待与唤醒(wait、notify、notifyAll)的使用技巧和注意事项,需要的朋友参考一下 本篇我们来研究一下 wait() notify() notifyAll() 。 DEMO1: wait() 与 notify() DEMO1 输出: 注意: 使用 wait
问题内容: 想象一下,您在Java中有一个典型的生产者- 消费者模式。为了提高效率,您要使用而不是在将新元素添加到队列时使用。如果两个生产者线程调用notify,是否保证将唤醒两个不同的正在等待的使用者线程?还是彼此之间很快触发的两个s导致同一用户线程排队两次唤醒?我找不到该部分描述此工作原理的API。Java是否有一些原子内部操作可仅一次唤醒线程? 如果仅一个消费者正在等待,则第二个通知将丢失,
我正在创建一个简单的web代理应用程序使用Java。基本上,main方法创建一个RequestReceiver对象,该对象具有侦听web浏览器http请求的ServerSocket。从ServerSocket.Accept()返回的套接字创建一个新的连接对象,并将其放入线程池中。
本文向大家介绍Java等待唤醒机制原理实例解析,包括了Java等待唤醒机制原理实例解析的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Java等待唤醒机制原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 线程的状态 首先了解一下什么是线程的状态,线程状态就是当线程被创建(new),并且启动(start)后,它不是一启动就进入
问题内容: 我写了一个永远不会停止的测试应用程序。它发出(是一个对象),但是我从不打电话通知。为什么此代码结束?尽管主线程在上同步,但生成的线程仍在运行,因此不会锁定该对象。 结果是主线程等待5秒钟,在此期间工作人员提供其输出。然后,在5秒钟后,程序退出。不等。如果主线程在5秒钟内没有进入睡眠状态(对此行进行了注释),则实际上将等到工作人员完成操作。当然,这里是一种使用方法,但是,出乎意料的是,它
我有一段代码 如您所见,我首先将标志设置为false,这样其中一个线程就可以进入Sum2Elements方法并将其更改为true,从而让所有人都等待。 我知道在同步代码中,只有一个线程可以完成它的任务,这里我有两个同步方法,这是否意味着两个线程在每次通知之后都在尝试执行这个方法? 如果是这样,那么一个线程是否不可能输入Sum2Elements,在另一个线程进入InsertElement之前将标志更