Java高并发编程详解系列-Guarded Suspension设计模式
导语
什么是Guarded Suspension模式,Suspension 意思是挂起,暂停的。而Guarded则表示担保的意思,连起来的就是确保挂起。也就是说当线程访问某个对象的时候,发现条件不满足,就暂时挂起等待条件满足的时候再次发起访问,这一点与Balking设计模式正好是相反的(Balking在遇到条件不满足的时候回放弃)。在Java并发包中BlockingQueue大量的使用了Guarded Suspension设计模式
文章目录
- Guarded Suspension设计模式
- 什么是Guarded Suspension 设计模式
- Guarded Suspension 示例
- 总结
Guarded Suspension设计模式
什么是Guarded Suspension 设计模式
Suspension 表示挂起、暂停的意思,而Guarded 则是担保的意思,连起来就是确保挂起。也就是当线程访问某个对象的时候,发现条件不满足,就暂时的挂起当条件满足的时候再次进行访问,这个设计与Balking设计模式刚好相反(Balking在遇到条件不满足的时候回主动放弃)
Guarded Suspension 设计模式是很多的设计模式的基础,例如生产消费模式,Worker Thread设计模式,等等。在Java并发包中的BlockingQueue也使用到了Guarded Suspension 设计模式。
在Java源码中java.util.concurrent.ArrayBlockingQueue类为BlockingQueue接口的实现类其中有两个方法是值得关注的
public boolean offer(E e) {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lock();try {if (count == items.length)return false;else {enqueue(e);return true;}} finally {lock.unlock();}
}private void enqueue(E x) {// assert lock.getHoldCount() == 1;// assert items[putIndex] == null;final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length)putIndex = 0;count++;notEmpty.signal();
}public E take() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == 0)notEmpty.await();return dequeue();} finally {lock.unlock();}
}private E dequeue() {// assert lock.getHoldCount() == 1;// assert items[takeIndex] != null;final Object[] items = this.items;@SuppressWarnings("unchecked")E x = (E) items[takeIndex];items[takeIndex] = null;if (++takeIndex == items.length)takeIndex = 0;count--;if (itrs != null)itrs.elementDequeued();notFull.signal();return x;
}
根据上面的思路设计了如下的实例
Guarded Suspension 示例
public class GuardedSuspensionQueue {//定义存放Integer类型的Queueprivate final LinkedList<Integer> queue = new LinkedList<>();//定义queue的最大容量为100private final int LIMIT = 100;//向queue中插入数据,如果queue中的元素超过最大容量,则会陷入阻塞public void offer(Integer data) throws InterruptedException {synchronized (this){//判断queue的当前元素是否超过LIMITwhile (queue.size()>=LIMIT){//当前线程进入到阻塞this.wait();}//插入元素并呼气take线程queue.addLast(data);this.notifyAll();}}//从队列中获取元素,如果队列此时为空,自会使得当前线程阻塞public Integer take() throws InterruptedException {synchronized(this){//如果队列为空while (queue.isEmpty()){//则挂起当前线程this.wait();}//通知offer线程可以继续插入数据this.notifyAll();return queue.removeFirst();}}
}
在GuardedSuspensionQueue中,需要保证线程安全的地方是queue,分别在take方法和offer方法中对应的临界值为空或者100的时候,当queue中的数据已经满了,如果线程调用了offer方法则会被挂起,同样的如果当这个queue没有数据的时候会调用take方法也会被挂起。这样就保证了线程的安全性。
Guarded Suspension设计模式是一个比较基础的设计模式,它关注的是当某个条件不满足时候的操作,从而防止出现数据不一致或者是超过临界值的控制范围。如下图
对于数据操作的空间就只有蓝色部分的内存,如果queue队列中的数据满的时候,对于所有的线程写入操作都进入到了挂起状态。当然当queue为空的时候对于所有线程的读取操作就进入到了挂起状态。通过这样可以保证了queue的高效利用率。不需要在频繁的创建和销毁队列。保证了公共资源的线程安全。至于具体有那些线程消费公共队列中的内容就是线程处理的问题。
总结
相对来说Guarded Suspension设计模式并不是一个复杂的模式而是比较简单的一个模式,从上面例子中可以看出使用也相对比较简单。Guarded Suspension 的关注点还是在于临界值的是否满足条件。当达到设置的临界值是相关线程会被挂起。在很多的设计场景中都有这种设计模式的影子。
Java高并发编程详解系列-Guarded Suspension设计模式相关推荐
- Java高并发编程详解系列-线程上下文设计模式及ThreadLocal详解
导语 在之前的分享中提到过一个概念就是线程之间的通信,都知道在线程之间的通信是一件很消耗资源的事情.但是又不得不去做的一件事情.为了保证多线程线程安全就必须进行线程之间的通信,保证每个线程获取到的 ...
- Java高并发编程详解系列-单线程执行设计模式
引言 首先介绍的这个技术有一个比较高大尚的英文名字叫做Single Thread Execution也就是说在同一时刻只能有一个线程访问共享资源,也就是说共享资源同一时间只能被一个线程访问,而这个共享 ...
- Java高并发编程详解系列-Java线程入门
根据自己学的知识加上从各个网站上收集的资料分享一下关于java高并发编程的知识点.对于代码示例会以Maven工程的形式分享到个人的GitHub上面. 首先介绍一下这个系列的东西是什么,这个系列自己 ...
- Java高并发编程详解系列-7种单例模式
引言 在之前的文章中从技术以及源代码的层面上分析了关于Java高并发的解决方式.这篇博客主要介绍关于单例设计模式.关于单例设计模式大家应该不会陌生,作为GoF23中设计模式中最为基础的设计模式,实现起 ...
- Java高并发编程详解系列-Future设计模式
导语 假设,在一个使用场景中有一个任务需要执行比较长的时间,通常需要等待任务执行结束之后或者是中途出错之后才能返回结果.在这个期间调用者只能等待,对于这个结果Future设计模式提供了一种凭据式的 ...
- Java高并发编程详解系列-类加载
之前在写关于JVM的时候提到过类加载机制,类加载机制也是在Java面试中被经常问道的一个问题,在这篇博客中就来了解一下关于类加载的知识. 类加载 在JVM执行Java程序的时候实际上执行的编译好的 ...
- Java高并发编程详解系列-线程安全数据同步
在多线程中最为复杂和最为重要的就是线程安全.多个线程访问同一个对象的时候会导致线程安全问题.通过加锁可以避免这种问题.但是在串行执行的过程中又不用考虑线程安全问题,而使用串行程序效率低没有办法将CPU ...
- Java高并发编程详解系列-不可变对象设计模式
导语 在开发中涉及到的所有关于多线程的问题都离不开共享资源的存在.那么什么是共享资源,共享资源就是被多个线程共同访问的数据资源,而且每个线程都会引起它的变化.伴随共享资源而生的新问题就是线程安全, ...
- Java高并发编程详解系列-线程上下文类加载
前面的分享中提到的最多的概念就是关于类加载器的概念,但是当我们查看Thread源码的时候会发现如下的两个方法,这两个方法就是获取或者设置线程的上下文类加载器的方法,那么为什么要设置这两个方法呢?这个就 ...
最新文章
- 邮箱性质--全选单选的操作和传值 用属性的name传值
- Flying to the Mars
- 说一说ffmpeg到处都在使用的ff_thread_once函数
- T(n) = 25T(n/5)+n^2的时间复杂度 计算方法
- AQS源码阅读笔记(一)
- uva 1626——Brackets sequence
- spring基础——<bean>scope属性
- C语言之文件读写探究(四):fwrite、fread(一次读写一块数据(二进制操作))
- Linux下SVN创建新的项目
- static,inline,volatile的作用
- ListView分页加载数据
- “百度快照劫持”到底是什么意思?
- python对数正态分布函数_python中的对数正态分布
- 最新微信小程序获取音频时长与实时获取播放进度
- NOIP模拟赛 17.10.10
- android 4.5屏幕,屏幕大也不怕 4.5吋起大屏续航手机推荐
- 大众中国纯电动战略“水土不服”?理想ONE冲击月销过万目标
- Java处理生僻字的问题
- 随机信号处理笔记 - ING
- 使用树莓派构建嵌入式C++调试环境
热门文章
- lora信号测试小助手_433m无线收发模块LoRaF30如何进行距离测试
- python数据按照分组进行频率分布_python实现读取类别频数数据画水平条形图
- python 打开excel并在屏幕上呈现_excel-检查文件是否在Python中打开
- Linux容器能否弥补IoT的安全短板?
- 《转载》struts旅程《2》
- 对request,session,application作用域形象理解
- 九个PHP很有用的功能
- Firefly 3288又一次制作android和lubuntu双系统固件
- 《iOS 9 开发指南》——第6章,第6.7节iOS 9控件的属性
- 研磨数据结构与算法-13删除二叉树节点