Java并发编程实战 第14章 构建自定义的同步工具
状态依赖性
定义:只有满足特定的状态才能继续执行某些操作(这些操作依赖于固定的状态,这些状态需要等待别的线程来满足)。
FutureTask,Semaphroe,BlockingQueue等,都是状态依赖性的类。
条件队列
条件对列:条件对列就是由于不满足继续的条件而被wait操作阻塞的线程队列。他们都在等待条件满足,然后被唤醒。
条件谓词:状态依赖性依赖的前提条件。如BlockingQueue中的isFull,isEmpty等。
条件等待中存在三个要素:加锁 + 条件谓词 + wait方法
wait方法和notify方法
我理解的wait方法:会释放锁+阻塞当前线程,放入条件对列,等待被唤醒,唤醒后,需要重新获得锁,获得锁之后继续执行wait那句代码所在的位置(即使wait在锁块的中间代码部分)。
notify(All)方法:只是唤醒条件队列中的线程。但是不释放锁。
使用wait notify方法的时候,一定要持有条件对列所属的锁。
使用轮询和休眠实现简单的状态依赖性阻塞
- while(true)
- {
- //这里不对循环上锁,不然这个锁就无法释放了,不对休眠上锁,休眠上锁,在休眠的时候别人也无法操作,永远都不可能有元素出去
- synchronized (this)
- {
- //如果队列不是满的,那么就放入元素
- if(!this.isFull())
- {
- this.doPut(v);
- return;
- }
- }
- //否则休眠,退出cpu占用
- Thread.sleep(SLEEP_GRANULARITY);
- }
- }
使用条件队列来实现状态依赖性阻塞
- public synchronized void put(V v) throws InterruptedException
- {
- while(this.isFull())
- {
- //这里挂起程序,会释放锁
- this.wait();
- }
- //如果队列不为满的,那么程序被唤醒之后从新获取锁
- this.doPut(v);
- //执行结束,唤醒其他队列
- this.notifyAll();
- }
注意上面要使用while。
对于监视器来说,wait操作产生的线程,都放在这个监视器唯一的条件队列里。
如果使用Lock,可以使用condition来产生不同的条件对列。
注意上面的 this.notifyAll();代码,将会唤醒这个监视器条件队列里所有等待的线程。其实这里只用唤醒因为empty阻塞的线程,而不用唤醒因为full阻塞的线程。
如果使用 this.notify(),只会随机唤醒一个,如果唤醒的是因为full堵塞的线程,那么就可能没有正常唤醒。影响性能,甚至造成活跃性的危险。
这种情况下,可以使用Lock和Condition来改造。
- protected final Lock lock = new ReentrantLock();
- private final Condition notFull = lock.newCondition();
- private final Condition notEmpty = lock.newCondition();
- public void put(T x) throws InterruptedException {
- lock.lock();
- try {
- while (count == items.length)
- notFull.await();
- items[tail] = x;
- if (++tail == items.length)
- tail = 0;
- ++count;
- notEmpty.signal();
- } finally {
- lock.unlock();
- }
- }
注意:这里不是signalAll。
阀门类
使用闭锁CountDownLatch,传入1的时候可以作为阀门开关。前提是在其他线程的第一步先执行开关的await。使用开关的countDown方法就可以打开开关。
但是这种阀门,只能打开,不能关闭。
使用wait和notifyAll来实现可重新关闭的阀门。
Condition
注意,由于Condition对象继承自Object,它也有wait,notify,notifyAll方法,其实它对应方法名字应该是await,signal,signalAll。
Java并发编程实战 第14章 构建自定义的同步工具的更多相关文章
- Java并发编程实战 第5章 构建基础模块
同步容器类 Vector和HashTable和Collections.synchronizedXXX 都是使用监视器模式实现的. 暂且不考虑性能问题,使用同步容器类要注意: 只能保证单个操作的同步. ...
- Java并发编程实战---第六章:任务执行
废话开篇 今天开始学习Java并发编程实战,很多大牛都推荐,所以为了能在并发编程的道路上留下点书本上的知识,所以也就有了这篇博文.今天主要学习的是任务执行章节,主要讲了任务执行定义.Executor. ...
- Java并发编程实战 第16章 Java内存模型
什么是内存模型 JMM(Java内存模型)规定了JVM必须遵循一组最小保证,这组保证规定了对变量的写入操作在何时将对其他线程可见. JMM为程序中所有的操作定义了一个偏序关系,称为Happens-Be ...
- 【java并发编程实战】第一章笔记
1.线程安全的定义 当多个线程访问某个类时,不管允许环境采用何种调度方式或者这些线程如何交替执行,这个类都能表现出正确的行为 如果一个类既不包含任何域,也不包含任何对其他类中域的引用.则它一定是无状态 ...
- Java并发编程实战 第8章 线程池的使用
合理的控制线程池的大小: 下面内容来自网络.不过跟作者说的一致.不想自己敲了.留个记录. 要想合理的配置线程池的大小,首先得分析任务的特性,可以从以下几个角度分析: 任务的性质:CPU密集型任务.IO ...
- java并发编程实战:第十四章----构建自定义的同步工具
一.状态依赖性管理 对于单线程程序,某个条件为假,那么这个条件将永远无法成真 在并发程序中,基于状态的条件可能会由于其他线程的操作而改变 可阻塞的状态依赖操作的结构 acquire lock on o ...
- Java并发编程实战 第3章 对象的共享
可见性 可见性是由于java对于多线程处理的内存模型导致的.这似乎是一种失败的设计,但是JVM却能充分的利用多核处理器的强大性能,例如在缺乏同步的情况下,Java内存模型允许编译器对操作顺序进行重排序 ...
- JAVA并发编程实战---第三章:对象的共享(2)
线程封闭 如果仅仅在单线程内访问数据,就不需要同步,这种技术被称为线程封闭,它是实现线程安全性的最简单的方式之一.当某个对象封闭在一个线程中时,这种方法将自动实现线程安全性,即使被封闭的对象本生不是线 ...
- 那些年读过的书《Java并发编程实战》一、构建线程安全类和并发应用程序的基础
1.线程安全的本质和线程安全的定义 (1)线程安全的本质 并发环境中,当多个线程同时操作对象状态时,如果没有统一的状态访问同步或者协同机制,不同的线程调度方式和不同的线程执行次序就会产生不同的不正确的 ...
随机推荐
- 基于form表单的极验滑动验证小案例
01.目录展示 02.url.py urlpatterns = [ path('admin/', admin.site.urls), path('login/',views.login), path( ...
- linux(centOS7)的基本操作(三) 用户、组、权限管理
用户和组 1.用户.组.家目录的概念 linux系统支持多用户,除了管理员,其他用户一般不应该使用root,而是应该向管理员申请一个账号.组类似于角色,系统可以通过组对有共性的用户进行统一管理.每个用 ...
- ping命令介绍
1.ping是TCP/IP协议的一部分,所以只要安装了TCP/IP协议就(无论windows或linux)都可以使用ping命令. 2.ping命令的原理:本机创建一个数据包发送给(ping对象)目标 ...
- Selenium 2自动化测试实战4(引用模块)
一.模组1.模组也叫类库或模块,引用模块 在python中,通过import….或from….import….的方式引用模块,下面引用time模块 import time print (time.ct ...
- Elasticsearch 6.2.3版本 同一个index新增type报错 Rejecting mapping update to [website] as the final mapping would have more than 1 type: [blog2, blog]
在website的index下已经存在一个名为blog的type.想在website下,新增一个名为blog2的type. 执行语句如下: PUT /website/blog2/1 { "t ...
- Python 测试代码覆盖率统计工具 coverage.py
安装 您可以通常的方式安装coverage.py.最简单的方法是使用pip: $ pip install coverage 要安装预发布版本,您需要指定--pre: $ pip install --p ...
- 6.3.2巴特沃斯(butterworth)低通滤波器
在本程序中,共有六个自定义函数,分别是: 1. myMagnitude(Mat & complexImg,Mat & magnitudeImage),在该函数中封装了Opencv中的 ...
- [转载]jsp上传文件
JSP 可以与 HTML form 标签一起使用,来允许用户上传文件到服务器.上传的文件可以是文本文件或图像文件或任何文档. 本章节我们使用 Servlet 来处理文件上传,使用到的文件有: uplo ...
- python 并发编程 多线程 互斥锁
互斥锁 并行变成串行,牺牲效率 保证数据安全,实现局部串行 保护不同的数据,应该加不同的锁 现在一个进程 可以有多个线程 所有线程都共享进程的地址空间 实现数据共享 共享带来问题就会出现竞争 竞争就会 ...
- CF486B OR in Matrix(构造+思维)
CF486B 一道有趣的思维题 由于or的性质可知只要a[i][j]为1那么b中第i行,第j列将都变成1 相反的,如果b[i][j]是0那么a中第i行,第j列都必须是0 根据第二个性质我们可以构造出a ...