状态依赖性

定义:只有满足特定的状态才能继续执行某些操作(这些操作依赖于固定的状态,这些状态需要等待别的线程来满足)。

FutureTask,Semaphroe,BlockingQueue等,都是状态依赖性的类。

条件队列

条件对列:条件对列就是由于不满足继续的条件而被wait操作阻塞的线程队列。他们都在等待条件满足,然后被唤醒。

条件谓词:状态依赖性依赖的前提条件。如BlockingQueue中的isFull,isEmpty等。

条件等待中存在三个要素:加锁 + 条件谓词 + wait方法

wait方法和notify方法

我理解的wait方法:会释放锁+阻塞当前线程,放入条件对列,等待被唤醒,唤醒后,需要重新获得锁,获得锁之后继续执行wait那句代码所在的位置(即使wait在锁块的中间代码部分)。

notify(All)方法:只是唤醒条件队列中的线程。但是不释放锁。

使用wait notify方法的时候,一定要持有条件对列所属的锁。

使用轮询和休眠实现简单的状态依赖性阻塞

  1. while(true)
  2.         {
  3.             //这里不对循环上锁,不然这个锁就无法释放了,不对休眠上锁,休眠上锁,在休眠的时候别人也无法操作,永远都不可能有元素出去
  4.             synchronized (this)
  5.             {
  6.                 //如果队列不是满的,那么就放入元素
  7.                 if(!this.isFull())
  8.                 {
  9.                     this.doPut(v);
  10.                     return;
  11.                 }
  12.             }
  13.             //否则休眠,退出cpu占用
  14.             Thread.sleep(SLEEP_GRANULARITY);
  15.         }
  16.     }

使用条件队列来实现状态依赖性阻塞

  1. public synchronized void put(V v) throws InterruptedException
  2.    {
  3.        while(this.isFull())
  4.        {
  5.            //这里挂起程序,会释放锁
  6.            this.wait();
  7.        }
  8.        //如果队列不为满的,那么程序被唤醒之后从新获取锁
  9.        this.doPut(v);
  10.        //执行结束,唤醒其他队列
  11.        this.notifyAll();
  12.    }

注意上面要使用while。

对于监视器来说,wait操作产生的线程,都放在这个监视器唯一的条件队列里。

如果使用Lock,可以使用condition来产生不同的条件对列。

注意上面的 this.notifyAll();代码,将会唤醒这个监视器条件队列里所有等待的线程。其实这里只用唤醒因为empty阻塞的线程,而不用唤醒因为full阻塞的线程。

如果使用 this.notify(),只会随机唤醒一个,如果唤醒的是因为full堵塞的线程,那么就可能没有正常唤醒。影响性能,甚至造成活跃性的危险。

这种情况下,可以使用Lock和Condition来改造。

  1. protected final Lock lock = new ReentrantLock();
  2. private final Condition notFull = lock.newCondition();
  3. private final Condition notEmpty = lock.newCondition();
  4.  public void put(T x) throws InterruptedException {
  5.         lock.lock();
  6.         try {
  7.             while (count == items.length)
  8.                 notFull.await();
  9.             items[tail] = x;
  10.             if (++tail == items.length)
  11.                 tail = 0;
  12.             ++count;
  13.             notEmpty.signal();
  14.         } finally {
  15.             lock.unlock();
  16.         }
  17.     }

注意:这里不是signalAll。

阀门类

使用闭锁CountDownLatch,传入1的时候可以作为阀门开关。前提是在其他线程的第一步先执行开关的await。使用开关的countDown方法就可以打开开关。

但是这种阀门,只能打开,不能关闭。

使用wait和notifyAll来实现可重新关闭的阀门。

Condition

注意,由于Condition对象继承自Object,它也有wait,notify,notifyAll方法,其实它对应方法名字应该是await,signal,signalAll。

转载于:https://www.cnblogs.com/xiaolang8762400/p/7074721.html

Java并发编程实战 第14章 构建自定义的同步工具相关推荐

  1. java并发编程实战:第十四章----构建自定义的同步工具

    一.状态依赖性管理 对于单线程程序,某个条件为假,那么这个条件将永远无法成真 在并发程序中,基于状态的条件可能会由于其他线程的操作而改变 1 可阻塞的状态依赖操作的结构 2 3 acquire loc ...

  2. Java并发编程实战 第4章 对象的组合

    Java监视器模式 java监视器模式就是在将共享的数据封装在一个类里面,然后然后所有访问或者修改这些数据的方法都标注为synchronize. 车辆追踪模拟: 使用监视器模式: CarTracker ...

  3. JAVA并发编程实战---第三章:对象的共享(2)

    线程封闭 如果仅仅在单线程内访问数据,就不需要同步,这种技术被称为线程封闭,它是实现线程安全性的最简单的方式之一.当某个对象封闭在一个线程中时,这种方法将自动实现线程安全性,即使被封闭的对象本生不是线 ...

  4. java并发编程实战-第三章-对象的共享

    3.1可见性 首先我们需要知道的是,java的线程都有自己独立的缓存,线程之间进行共享变量的交互是通过自身和缓存和主存的交互实现的. 如果线程的每次更改缓存都刷入主存,主存每次被一个线程的缓存修改,都 ...

  5. JAVA并发编程实战---第三章:对象的共享

    在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程序中,要对内存操作的执行顺序进行判断几乎无法得到正确的结果. 非原子的64位操作 当 ...

  6. Java并发编程实战 第13章 显式锁

    接口Lock的实现类: ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock Reentra ...

  7. 《Java并发编程实战》【第一部分 基础知识】

    文章目录 第1章 简介 1.1 并发简史 1.2 线程的优势 1.2.1 发挥多处理器的强大能力 1.2.2 建模的简单性 1.2.3 异步事件的简化处理 1.2.4 响应更灵敏的用户界面 1.3 线 ...

  8. Java并发编程实战读书笔记三

    第七章 取消和关闭 Java没有提供任何机制来安全的终止线程,虽然 Thread.stop 和 suspend 等方法提供了这样的机制,但由于存在着一些严重的陷,因此应该避免使用 7.1任务取消 7. ...

  9. java并发编程实战学习(3)--基础构建模块

    转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put ...

最新文章

  1. 路由器、路由与路由表
  2. SAP PM IW33里查看维护订单相关的维护计划
  3. Qt5.3.2openglVS2010_QSqlField_字段类型
  4. Redis进阶-如何从海量的 key 中找出特定的key列表 Scan详解
  5. 深度学习入门笔记系列(一)——深度学习框架 tensorflow 的介绍与安装
  6. jdbc thin连接oracle10,setSavepoint方法报错解决办法
  7. 几个小时后,我学数据库,找到一些代码
  8. 服务器型号惠普RX3600,384854-B21 389344-001 146G SAS 15K 3.5寸HP服务器硬盘批发
  9. 牛掰本机限速软件appband
  10. 推荐一款图片轮换jQuery插件
  11. 一个神秘 URL 酿大祸,差点让我背锅!
  12. 找出单身狗java_Java单身狗 —— 单例模式
  13. python:使用requests,bs4爬取mmjpg上的图片
  14. autojs利用坚果云实现云更新
  15. 智和网管平台-真正开放源码的网元管理系统(EMS)
  16. Ajax介绍和基本使用
  17. 直播倒计时android,直播代码,Android实现验证码倒计时
  18. cmd的tree命令使用方法
  19. 经济基础知识(初级)【3】
  20. 百度离线地图 —— 瓦片地图下载

热门文章

  1. 【机器学习】 - 目标检测 - VOC格式数据集介绍与自己制作
  2. 【基于Python】 - 人工智能机器学习深度学习数据分析 - 常见问题,常用的套路与操作(持续更新)
  3. 【HDU - 5869】Different GCD Subarray Query(思维,数学,gcd,离线处理,查询区间不同数,树状数组 或 二分RMQ)
  4. 【CodeForces - 520C】DNA Alignment (快速幂,思维)
  5. Apollo进阶课程㉟丨Apollo ROS原理—4
  6. 机器学习笔记(4):多变量线性回归
  7. android 退出函数,android – 关闭应用程序与退出按钮
  8. HTML简单注册页面
  9. java屏蔽编译告警_java-禁止JAXB生成的类上的编译器警告
  10. java 监听器 分类_java过滤器和监听器详解 分类: 学习专区