wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放),调用wait方法的一个或多个线程就会解除wait状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

 2)当前线程必须拥有此对象的monitor(即锁),才能调用某个对象的wait()方法能让当前线程阻塞,

(这种阻塞是通过提前释放synchronized锁,重新去请求锁导致的阻塞,这种请求必须有其他线程通过notify()或者notifyAll()唤醒重新竞争获得锁)

 3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

(notify()或者notifyAll()方法并不是真正释放锁,必须等到synchronized方法或者语法块执行完才真正释放锁)

 4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程,唤醒的线程获得锁的概率是随机的,取决于cpu调度

例子1(错误使用导致线程阻塞):三个线程,线程3先拥有sum对象的锁,然后通过sum.notify()方法通知等待sum锁的线程去获得锁,但是这个时候线程1,2并没有处于wait()导致的阻塞状态,而是在synchronized方法块处阻塞了,所以,这次notify()根本没有通知到线程1,2。然后线程3正常结束,释放掉sum锁,这个时候,线程1就立刻获得了sum对象的锁(通过synchronized获得),然后调用sum.wait()方法释放掉sum的锁,线程2随后获得了sum对象的线程锁(通过synchronized获得),这个时候线程1,2都处于阻塞状态,但是悲催的是,这之后再也没有线程主动调用sum.notify()或者notifyAll()方法显示唤醒这两个线程,所以程序阻塞

  1. public class CyclicBarrierTest {
  2. public static void main(String[] args) throws Exception {
  3. final Sum sum=new Sum();
  4. new Thread(new Runnable() {
  5. @Override
  6. public void  run() {
  7. try {
  8. synchronized (sum) {
  9. System.out.println("thread3 get lock");
  10. sum.sum();
  11. sum.notifyAll(); //此时唤醒没有作用,没有线程等待
  12. Thread.sleep(2000);
  13. System.out.println("thread3 really release lock");
  14. }
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. }).start();
  20. new Thread(new Runnable() {
  21. @Override
  22. public void  run() {
  23. try {
  24. synchronized (sum) {
  25. System.out.println("thread1 get lock");
  26. sum.wait();//主动释放掉sum对象锁
  27. System.out.println(sum.total);
  28. System.out.println("thread1 release lock");
  29. }
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }).start();
  35. new Thread(new Runnable() {
  36. @Override
  37. public void  run() {
  38. try {
  39. synchronized (sum) {
  40. System.out.println("thread2 get lock");
  41. sum.wait();  //释放sum的对象锁,等待其他对象唤醒(其他对象释放sum锁)
  42. System.out.println(sum.total);
  43. System.out.println("thread2 release lock");
  44. }
  45. } catch (Exception e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }).start();
  50. }
  51. }
  52. class Sum{
  53. public Integer total=0;
  54. public void  sum() throws Exception{
  55. total=100;
  56. Thread.sleep(5000);
  57. }
  58. }

运行结果:

  1. thread3 get lock
  2. thread3 really release lock
  3. thread2 get lock
  4. thread1 get lock
  5. //程序后面一直阻塞

例子2:还是上面程序,顺序不同,把线程3放到最下面。最后线程1,2都因为没有再次获得线程导致线程阻塞

运行过程:

线程1先运行获得sum对象锁(通过synchronized),但是随后执行了sum.wait()方法,主动释放掉了sum对象锁,然后线程2获得了sum对象锁(通过synchronized),也通过sum.wait()失去sum的对象锁,最后线程3获得了sum对象锁(通过synchronized),主动通过sum.notify()通知了线程1或者2,假设是1,线程1重新通过notify()/notifyAll()的方式获得了锁,然后执行完毕,随后线程释放锁,然后这个时候线程2成功获得锁,执行完毕。

  1. public class CyclicBarrierTest {
  2. public static void main(String[] args) throws Exception {
  3. final Sum sum=new Sum();
  4. new Thread(new Runnable() {
  5. @Override
  6. public void  run() {
  7. try {
  8. synchronized (sum) {
  9. System.out.println("thread1 get lock");
  10. sum.wait();//主动释放sum对象锁,等待唤醒
  11. System.out.println(sum.total);
  12. System.out.println("thread1 release lock");
  13. }
  14. } catch (Exception e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }).start();
  19. new Thread(new Runnable() {
  20. @Override
  21. public void  run() {
  22. try {
  23. synchronized (sum) {
  24. System.out.println("thread2 get lock");
  25. sum.wait();  //主动释放sum对象锁,等待唤醒
  26. System.out.println(sum.total);
  27. System.out.println("thread2 release lock");
  28. }
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }).start();
  34. new Thread(new Runnable() {
  35. @Override
  36. public void  run() {
  37. try {
  38. synchronized (sum) {
  39. System.out.println("thread3 get lock");
  40. sum.sum();
  41. sum.notifyAll();//唤醒其他等待线程(线程1,2)
  42. Thread.sleep(2000);
  43. System.out.println("thread3 really release lock");
  44. }
  45. } catch (Exception e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. }).start();
  50. }
  51. }
  52. class Sum{
  53. public Integer total=0;
  54. public void  sum() throws Exception{
  55. total=100;
  56. Thread.sleep(5000);
  57. }
  58. }

执行结果:

    1. thread1 get lock
    2. thread2 get lock
    3. thread3 get lock
    4. thread3 really release lock
    5. 100
    6. thread2 release lock
    7. 100
    8. thread1 release lock

转自 https://blog.csdn.net/azhegps/article/details/63031562

java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)的更多相关文章

  1. Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  2. 【Java并发系列02】Object的wait()、notify()、notifyAll()方法使用

    一.前言 对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多. 二.线程安全基本知识 首先应该记住以下基本点,先背下来也无妨: ...

  3. java基础知识回顾之java Thread类学习(九)--wait和notify区别

    wait和sleep区别:  相同点:调用wait,sleep方法都可以是线程进入阻塞状态,让出cpu的执行权. 不同点:1.sleep必须指定时间,但是wait方法可以指定时间,也可以不指定时间. ...

  4. java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

    1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以 ...

  5. Java多线程系列4 线程交互(wait和notify方法)

    wait()/ notify()/ notifyAll() 任何Object对象都可以作为这三个方法的主调,但是不推荐线程对象调用这些方法. 1使用wait().notify()和notifyAll( ...

  6. 【Java并发编程】9、非阻塞同步算法与CAS(Compare and Swap)无锁算法

    转自:http://www.cnblogs.com/Mainz/p/3546347.html?utm_source=tuicool&utm_medium=referral 锁(lock)的代价 ...

  7. notify,wait,synchronized实现线程间通知

    wait阻塞线程释放锁:notify使wait所在的线程被唤醒在次获得锁,并执行,但要等到notify所在的线程代码全部执行后! 示例代码如下: package com.vhbi.service.im ...

  8. 码农会锁,synchronized 对象头结构(mark-word、Klass Pointer)、指针压缩、锁竞争,源码解毒、深度分析!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 感觉什么都不会,从哪开始呀! 这是最近我总能被问到的问题,也确实是.一个初入编程职场 ...

  9. 背水一战 Windows 10 (113) - 锁屏: 将 Application 的 Badge 通知和 Tile 通知发送到锁屏, 将 secondary tile 的 Badge 通知和 Tile 通知发送到锁屏

    [源码下载] 背水一战 Windows 10 (113) - 锁屏: 将 Application 的 Badge 通知和 Tile 通知发送到锁屏, 将 secondary tile 的 Badge ...

随机推荐

  1. 清北·NOIP2017济南考前冲刺班 DAY1 morning

    立方数(cubic) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK定义了一个数叫“立方数”,若一个数可以被写作是一个正整数的3次方,则这个数就是立方数 ...

  2. Oracle remove duplicate

    DELETE FROM your_table WHERE rowid not in (SELECT MIN(rowid) FROM your_table GROUP BY column1, colum ...

  3. Redis(二)linux下redis安装

    上篇讲解了redis在windows下的安装,接下来看看在linux下如何安装redis(纯菜鸟入门级别)? (1)redis的下载及编译 这里,首先进入存放文件目录(我的云服务器的是:cd /jel ...

  4. 蛋疼的VS2010 tab group

    http://superuser.com/questions/232031/why-does-my-visual-studio-2010-default-to-a-horizontal-windows ...

  5. 【mybatis】时间范围 处理时间格式问题 + 查询当天 本月 本年 + 按当天 当月 范围 查询 分组

    1.mybatis中查询时间范围处理: 例如2018-05-22 ~2018-05-23 则查出来的数据仅能查到2018-05-22的,查不到2018-05-23的数据! 为什么会这样? 明明时间字段 ...

  6. [转载] K3 K3c 最简单无损开壳方法

    只用一把螺丝刀就行了,其它什么撬棒  信用卡  撬片等 拆机工具一概不用.拆了5台,只有一台断了一个扣口. 1. 把底部4个螺丝拿掉.2.把路由如图放在桌子上,路由平行于身体,注意是立着放 使路由与桌 ...

  7. Linux内核锁与中断处理

    Linux内核锁 在Linux内核里面,一般采用了如下几种锁的机制,来保证多线程的同步与互斥: (1)原子操作 atomic_t v: void atomic_set(atomic_t *v, int ...

  8. OpenGL.Vertex Array Object (VAO) 【转】

    http://www.cppblog.com/init/archive/2012/02/21/166098.html 一 OpenGL抛弃glEnable(),glColor(),glVertex() ...

  9. 在scala中:: , +:, :+, :::, +++的区别总结

    初学Scala的人都会被Seq的各种操作符所confuse.下面简单列举一下各个Seq操作符的区别. 4种操作符的区别和联系 :: 该方法被称为cons,意为构造,向队列的头部追加数据,创造新的列表. ...

  10. 【Consul】 分布式环境中的服务注册和发现利器

    参考资料: http://www.cnblogs.com/shanyou/p/4695131.html http://blog.csdn.net/viewcode/article/details/45 ...