`
xiaoZ5919
  • 浏览: 405470 次
  • 性别: Icon_minigender_1
  • 来自: 安平人@北京
博客专栏
Group-logo
Netty学习笔记
浏览量:73253
社区版块
存档分类
最新评论

wait-notify的另一种情况

 
阅读更多
wait-notify用在经典的生产者-消费者模型。一般代码都是先初始化consumer,然后再初始化producer,程序正常运行。这是带有wait()先进入同步语句块,带有notifyAll()的后进入同步语句块。现在反过来带有notifyAll()先进入同步语句块,儿带有wait()的后进入语句块,这时候程序会一直阻塞,觉得很蹊跷,带着这个对synchronized,wait,notify又深入研究了一番。有一些结论和大家分享一下,首先来看synchronized,这个大家都很清楚,相当于排他锁谁先持有,其他线程必须得等待直到释放。依据这样的结论,
场景一 两个线程同时执行synchronized语句块,肯定只有一个线程成功,而另外一个阻塞。
下面的代码验证了结论:
            synchronized (lock) {
//                    for(int i = 0; i < 1000000;i++);
//                lock.notify();
                try {
                    Thread.sleep(50000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "notify other!");
            }
Thread-1被synchronized阻塞,Thread-0进入语句块执行sleep方法


 
当Thread-0执行完毕释放锁,Thread-1开始执行。此时Thread-0消亡


 
 
场景二 两个synchronized块中执行wait()的线程,会先后进入语句块,而不是其中一个等待另外一个执行完毕以后再进入。为什么会这样呢?我又重新看了一下jdk的comment发现,The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread
 notifies threads waiting on this object's monitor to wake up。wait首先释放同步语句块的锁,再执行wait,此时其他线程就能进入了。
  synchronized (lock) {
//                    for(int i = 0; i < 1000000;i++);
//                lock.notify();
                try {
                    Thread.sleep(50000);
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "notify other!");
            }


 
场景三,回到开始描述的场景,首先notify的线程先进入,wait的后进入。就会导致看似notify不生效。


 


 
看第二张堆栈图,一切就都明白了,注意看waiting on 和waiting to。synchronized和wait()虽然是监控的同一对象,但不是一回事儿。synchronized只有其他线程释放了锁,其他线程才能获得锁,而wait只能由notify唤醒。还原一下整个过程,notify先进入同步语句块,这时wait的wait to lock等待进入。
后来再到执行notify的时候其实是没用的,wait还被阻塞在synchronized之外。再后来退出同步块,带有 wait的语句块进入执行wait操作,就一直waiting on了,此时貌似notify没起到作用。
  • 大小: 11.2 KB
  • 大小: 5.9 KB
  • 大小: 14.7 KB
  • 大小: 10.1 KB
  • 大小: 7.6 KB
0
4
分享到:
评论
2 楼 xiaoZ5919 2013-06-19  
shenzhang722 写道
你说的很对,这个就是wait和notify的一个特性,也就是说如果notify比wait先调用,后面的wait很有可能就不会被唤醒

因此,最好加上一个条件变量,比如boolean shouldWait = true;

synchronized(object) {
    shouldWait = false;
    object.notify();
}


synchronized(object) {
     while (shouldWait) {
         object.wait();
     }
}

好主意
1 楼 shenzhang722 2013-06-19  
你说的很对,这个就是wait和notify的一个特性,也就是说如果notify比wait先调用,后面的wait很有可能就不会被唤醒

因此,最好加上一个条件变量,比如boolean shouldWait = true;

synchronized(object) {
    shouldWait = false;
    object.notify();
}


synchronized(object) {
     while (shouldWait) {
         object.wait();
     }
}

相关推荐

    java代码-wait-notify 生产者消费者

    在Java编程中,"生产者消费者"模型是一种常见的多线程问题解决策略,它通过共享资源来实现数据的生产和消费。在这个模型中,通常有两个线程:一个扮演生产者的角色,负责生成数据;另一个扮演消费者的角色,负责处理...

    Java使用wait() notify()方法操作共享资源详解

    总结来说,Java中的wait()、notify()和notifyAll()方法与`synchronized`关键字一起,为开发者提供了一种有效管理多线程间共享资源的方式,防止了线程间的冲突,实现了线程的同步和协作。在实际开发中,熟练掌握这些...

    Object.wait()与Object.notify()的用法详细解析

    另一种带有毫秒和纳秒参数,线程会在指定时间后自动唤醒,除非提前被其他线程唤醒。 `notify()`方法则用来唤醒在该对象上等待的一个线程,这个线程会被放入可运行队列,但并不保证立即执行,而是由JVM调度决定。而`...

    java sleep()和wait()

    - 第一种形式没有超时时间,线程将一直等待直到被另一个线程唤醒。 - 第二种和第三种形式设置了等待的超时时间,如果超时时间内没有被唤醒,线程将自动恢复执行。 ##### 2.3 使用场景 `wait()`方法通常用于以下几种...

    Java多线程-多线程知识点总结和企业真题

    - **不同点**:一种是类的继承,另一种是接口的实现。通常推荐使用实现`Runnable`接口的方式,因为它避免了类的单继承限制,并且更易于处理共享数据的问题。 ##### (3)Thread类的常用结构 1. **构造器**: - `...

    Java多线程-线程间的通信

    3. **交替打印**:线程打印完一个数字后,使用`lock.notify()`通知另一个线程可以开始执行。调用`lock.wait()`让当前线程等待,直到被唤醒。 4. **异常处理**:捕获`InterruptedException`,以避免线程因异常而终止...

    java 多线程-线程通信实例讲解

    例如,一个线程(线程A)可能负责生产数据,而另一个线程(线程B)则负责处理这些数据。线程A可以通过修改共享对象的状态(如设置一个布尔标志`hasDataToProcess`为`true`)来向线程B发出信号。线程B则通过检查这个...

    java10个线程按照顺序打印1-100

    5. **CountDownLatch**:`java.util.concurrent.CountDownLatch`是另一种同步辅助类,它允许一个或多个线程等待其他线程完成操作。在顺序打印的例子中,可以设置计数器为100,每个线程打印一个数字后减少计数器,...

    java问题定位技术+性能优化

    - **5.4 另一种异常陷阱-连续的关键接口调用** - 处理连续的API调用时,需要确保异常处理正确,避免资源泄漏。 #### 六、常见的Java泥潭 - **6.1 不稳定的Runtime.getRuntime().exec()** - 使用`Runtime....

    05-Java多线程并发编程JUC.pdf

    - 超时等待(Timed Waiting):线程在指定的时间内等待另一个线程执行操作。 - 终止(Terminated):线程的run()方法执行完毕后终止。 2. 线程的创建与启动 创建线程通常有两种方式: - 继承Thread类:创建一个...

    illy-Java.Threads.2nd.Edition

    - **Runnable接口**:另一种创建线程的方式是实现`Runnable`接口,并将其实例传递给`Thread`构造函数。 - **线程生命周期**:线程的状态包括新建、就绪、运行、阻塞和死亡等阶段。 - **线程命名**:可以通过设置线程...

    procon.rar_ProCon.d_生产 者- 消费者 问题_生产者

    1. **信号量(Semaphore)**:信号量是一种用于控制多个线程对共享资源访问的同步机制。它可以分为两种类型:二进制信号量(只能取0或1,相当于一个锁)和计数信号量(可以有任意非负整数值)。在生产者-消费者问题...

    java多线程2

    在Java多线程编程中,有时会遇到这样一种情况:一个线程(例如线程A)在执行的过程中,需要等待另一个线程(例如线程B)完成某项任务后才能继续执行。这种线程间的依赖关系通常被称为线程异步通信。本文将通过一个...

    java笔试题大集合及答案(另附各大公司笔试题)

    例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望...

    2018年蚂蚁课堂(每特教育)-Java工程师面试宝典-V1.0

    - `Condition`接口提供了一种替代`Object`类中`wait`和`notify`方法的机制,更加灵活和强大。 - 可以通过`Lock`接口的实现类(如`ReentrantLock`)获取`Condition`对象,用于实现更复杂的线程同步逻辑。 - **如何...

    s2-java.zip

    - Runnable接口:另一种实现多线程的方式,实现该接口的类可以作为Thread的参数。 - 线程同步:包括synchronized关键字、wait()、notify()和notifyAll()方法,防止数据竞争。 这些知识点覆盖了Java面向对象编程的...

    java编程 ---线程

    线程的基本控制包括:`sleep()`让线程暂停一段时间,`join()`使当前线程等待另一个线程结束,`yield()`让当前线程让出CPU使用权,以及`interrupt()`中断线程。 **4. 使用`synchronized`关键字** `synchronized`用于...

    Java多线程技术在网络通信系统中的应用.pdf

    wait/notify机制是另一种重要的线程间通信手段,它允许线程在执行到某个点时可以主动让出CPU,直到其他线程通过notify方法通知它再次获得CPU。 在多线程环境下,线程安全问题不容忽视。线程安全问题指的是当多个...

    Java并发编程面试题(2022最新版)

    - 上下文切换是指CPU从一个线程切换到另一个线程时,保存当前线程的状态并将新的线程状态加载到CPU的过程。 - 导致上下文切换的原因包括但不限于:时间片到期、I/O操作阻塞等。 **守护线程和用户线程的区别** - **...

Global site tag (gtag.js) - Google Analytics