由AbstractQueuedSynchronizer和ReentrantLock来看模版方法模式
在学完volatile和CAS之后,近几天在撸AbstractQueuedSynchronizer(AQS)的源代码,很多并发工具都是基于AQS来实现的,这也是并发专家Doug Lea的初衷,通过写一个这样的基础工具来提高j.u.c的灵活性。具体可以看这篇论文的一段原文,我摘录一下:
As is well-known (see e.g., [2]) nearly any synchronizer can be used to implement nearly any other. For example, it is possible to build semaphores from reentrant locks, and vice versa. However,doing so often entails enough complexity, overhead, and inflexibility to be at best a second-rate engineering option.Further, it is conceptually unattractive. If none of these constructs are intrinsically more primitive than the others, developers should not be compelled to arbitrarily choose one of them as a basis for building others. Instead, JSR166 establishes a small framework centered on class AbstractQueuedSynchronizer,that provides common mechanics that are used by most of the provided synchronizers in the package, as well as other classes that users may define themselves.
翻译下来大致的意思就是,如果使用信号量、锁等互为彼此实现,这样一种设计只会让问题变得复杂而且缺乏灵活性,既然这样,JSR166提出了AQS来作为基础工具来对外提供一种通用的机制。
AQS的设计和实现非常复杂,所以我打算通过DEBUG的方式看下内部是如何实现的,在看源码的过程中顺便学习了一个设计模式-模板方法。
1、模板方法结构
模板方法的本质其实就是类的继承,模板方法模式需要开发抽象类和具体子类的设计之间的协作,我们实际工作中应该有很多这样的场景,比如我们通常会在业务逻辑层定义好Service类的抽象方法,而实际的业务逻辑实现会交给ServiceImpl类。模板方法模式的类结构图大致如下:

图一
抽象模板(AbstractTemplate)角色有如下责任:
定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。定义并实现了一个模板方法,这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。AbstractQueuedSynchronizer就是这样一个抽象模板。
具体模板(ConcreteTemplate)角色又有如下责任:
实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。ReentrantLock算是这样一个具体模板,不过ReentrantLock把自己的实现又委托给了内部实现类Sync。
模板模式的关键是:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑。每当定义一个新的子类时,不要按照控制流程的思路去想,而应当按照“责任”的思路去想。换言之,应当考虑哪些操作是必须置换掉的,哪些操作是可以置换掉的,以及哪些操作是不可以置换掉的。使用模板模式可以使这些责任变得清晰。
2、模板方法模式中的方法
模板方法中的方法可以分为两大类:模板方法和基本方法。
模板方法:一个模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。一个抽象类可以有任意多个模板方法,而不限于一个。每一个模板方法都可以调用任意多个具体方法。
基本方法:基本方法又可以分为三种:抽象方法(Abstract Method)、具体方法(Concrete Method)和钩子方法(Hook Method)。
抽象方法:一个抽象方法由抽象类声明,由具体子类实现。在Java语言里抽象方法以abstract关键字标示。
具体方法:一个具体方法由抽象类声明并实现,而子类并不实现或置换。
钩子方法:一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空实现,作为方法的默认实现。
3、由AbstractQueuedSynchronizer和ReentrantLock来看模版方法模式
以ReentrantLock的lock方法为例来看下模板方法的体现。具体代码如下:
public class MutexDemo {
// private static Mutex mutex = new Mutex();
private static ReentrantLock mutex = new ReentrantLock();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(() -> {
mutex.lock();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mutex.unlock();
}
});
thread.start();
}
}
}
默认是以非公平锁来初始化ReentrantLock,所以方法中ReentrantLock将自己的行为委托给NonfairSync,NonfairSync继承Sync,Sync又继承了AbstractQueuedSynchronizer。在整个过程中AbstractQueuedSynchronizer的方法acquire其实就是模板模式里面的模板方法,方法release也是一样的,这两个方法是整套框架里面的顶级逻辑。在这个顶级逻辑之外,Sync给出了lock方法,这是一个抽象方法,下设2种实现,分别是公平锁FairSync和非公平锁NonfairSync。在顶级逻辑里面还有方法的具体方法实现,比如addWaiter和acquireQueued。另外还有一个钩子方法,如tryAcquire,在AQS里面这个钩子方法是没有具体的实现的,具体的实现交给了NonfairSync。感兴趣的读者可以按照这思路跟踪下代码,然后理解一下模板方法这个设计模式。
参考资料:
https://github.com/lingjiango/ConcurrentProgramPractice
http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html
由AbstractQueuedSynchronizer和ReentrantLock来看模版方法模式的更多相关文章
- 设计模式(java)--模版方法模式之任务分配
转自:http://blog.csdn.net/zhengzhb/article/details/7405608 定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构 ...
- [Head First设计模式]云南米线馆中的设计模式——模版方法模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- JS常用的设计模式(10)——模版方法模式
模式方法是预先定义一组算法,先把算法的不变部分抽象到父类,再将另外一些可变的步骤延迟到子类去实现.听起来有点像工厂模式( 非前面说过的简单工厂模式 ). 最大的区别是,工厂模式的意图是根据子类的实现最 ...
- Python设计模式——模版方法模式
1.模版方法模式 做题的列子: 需求:有两个学生,要回答问题,写出自己的答案 #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class Stude ...
- 【设计模式 - 23】之模版方法模式(Template)
1 模式简介 模版方法模式的定义: 模版方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 模版方法模 ...
- Chapter 10 模版方法模式
我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模版模式来处理. 模版方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模 ...
- 第13章 模版方法模式(Template Method)
原文 第13章 模版方法模式(Template Method) 模板模式 模板模式 举例:模拟下数据库的update方法,先删除在插入. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
- [Python设计模式] 第10章 怎么出试卷?——模版方法模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 小时候数学老师的随堂测验,都是老师在黑板上写题目,学生在下边抄,然后再做题 ...
- NET设计模式 第二部分 行为型模式(15):模版方法模式(Template Method)
摘要:Template Method模式是比较简单的设计模式之一,但它却是代码复用的一项基本的技术,在类库中尤其重要. 主要内容 1.概述 2.Template Method解说 3..NET中的Te ...
随机推荐
- [微信小程序]编译.wxss出错,2 not found
小程序新建项目就出错:2 not found 编译.wxss文件出错(不是一般的郁闷,新建项目就报错...) 大概的情况是开发工具没有更新.或更新不到, 第一,可以删掉开发工具重新下载最新安装: 第 ...
- java数组和集合的相互转换
由于在学习过程中经常碰到这么一个问题,就是java中几种装数据的容器之间的转换,所以写了这篇随笔专门来总结这些转换方法. 数组转集合: 1.遍历,最常用的方法,但是过程会繁琐一点 int arrs[] ...
- Canvas中绘制贝塞尔曲线
① 什么是贝塞尔曲线? 在数学的数值分析领域中,贝济埃曲线(英语:Bézier curve,亦作“贝塞尔”)是计算机图形学中相当重要的参数曲线.更高维度的广泛化贝济埃曲线就称作贝济埃曲面,其中贝济埃三 ...
- 如何在微信小程序定义全局变量、全局函数、如何实现 函数复用 模块化开发等问题详解
1.如何定义全局数据 在app.js的App({})中定义的数据或函数都是全局的,在页面中可以通过var app = getApp(); app.function/key的方式调用,不过我们没有必要 ...
- 使用SIP Servlet为Java EE添加语音功能
会话发起协议(Session Initiation Protocol,SIP)是一种信号传输协议,用于建立.修改和终止两个端点之间的会话.SIP 可用于建立 两方呼叫.多方呼叫,或者甚至 Intern ...
- 使用Nginx做图片服务器时候,配置之后图片访问一直是 404问题解决
我的错误配置是: 服务器文件根地址: 想通过浏览器输入这个地址访问到图片: 但是会发现文件找不到会一直404,原因是根路径配置错误,来看下root路径原理: root 配置的意思是,会在root配置的 ...
- RabbitQM(消息duilie)
前言:RabbitMQ 是实现 AMQP(Advanced Message Queuing Protocol 高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息, ...
- 如何设置使chrome新标签页中打开链接自动跳转到新标签页?
在新标签打开链接的时候这样点选 Ctrl+左键 或者 鼠标中键 或者 右键链接选择'新标签页中打开链接', 可实现出现新标签页但不自动跳转 但是这个有问题, 即, 新标签只是在背景打开, 操作后并不会 ...
- AutoFac - 将 autofac 应用于MVC多层项目
一.前言 AutoFac是.NET平台下的一款著名的IoC Container,它可以让我们很轻松的解除项目中服务类的接口与客户类的接口实现类之间的依赖关系,从而降低系统各模块之间耦合程度以提高系统的 ...
- ReentrantLock 实现原理
使用 synchronize 来做同步处理时,锁的获取和释放都是隐式的,实现的原理是通过编译后加上不同的机器指令来实现. 而 ReentrantLock 就是一个普通的类,它是基于 AQS(Abstr ...