在学完volatileCAS之后,近几天在撸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来看模版方法模式的更多相关文章

  1. 设计模式(java)--模版方法模式之任务分配

    转自:http://blog.csdn.net/zhengzhb/article/details/7405608 定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构 ...

  2. [Head First设计模式]云南米线馆中的设计模式——模版方法模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  3. JS常用的设计模式(10)——模版方法模式

    模式方法是预先定义一组算法,先把算法的不变部分抽象到父类,再将另外一些可变的步骤延迟到子类去实现.听起来有点像工厂模式( 非前面说过的简单工厂模式 ). 最大的区别是,工厂模式的意图是根据子类的实现最 ...

  4. Python设计模式——模版方法模式

    1.模版方法模式 做题的列子: 需求:有两个学生,要回答问题,写出自己的答案 #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class Stude ...

  5. 【设计模式 - 23】之模版方法模式(Template)

    1      模式简介 模版方法模式的定义: 模版方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 模版方法模 ...

  6. Chapter 10 模版方法模式

    我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模版模式来处理. 模版方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模 ...

  7. 第13章 模版方法模式(Template Method)

    原文  第13章 模版方法模式(Template Method) 模板模式 模板模式 举例:模拟下数据库的update方法,先删除在插入. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...

  8. [Python设计模式] 第10章 怎么出试卷?——模版方法模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目 小时候数学老师的随堂测验,都是老师在黑板上写题目,学生在下边抄,然后再做题 ...

  9. NET设计模式 第二部分 行为型模式(15):模版方法模式(Template Method)

    摘要:Template Method模式是比较简单的设计模式之一,但它却是代码复用的一项基本的技术,在类库中尤其重要. 主要内容 1.概述 2.Template Method解说 3..NET中的Te ...

随机推荐

  1. 轮播效果/cursor

    cursor属性:改变鼠标中的属性 例如: cursor:pointer(鼠标移动上去变小手) <!doctype html> <html> <head> < ...

  2. SQL基本注入演示

    作者:ZERO 所属团队:Arctic Shell 参考文献:<sql注入攻击与防御> 使用平台:pikachu漏洞练习平台 导语:  在owasp发布的top10排行榜中注入漏洞一直是危 ...

  3. [Swift]LeetCode684. 冗余连接 | Redundant Connection

    In this problem, a tree is an undirected graph that is connected and has no cycles. The given input ...

  4. Docker 搭建pxc集群 + haproxy + keepalived 高可用(二)

    上一节我们有了两个分片的pxc集群,这一节我们接着安装haproxy和keepalived的实现集群的高可用 一.先下载haproxy的镜像 [root@localhost ~]# docker pu ...

  5. Python档案袋( 进程与协程 )

    Python的进程和线程是使用的操作系统的原生线程和进程,其是去调用操作系统的相应接口实现 进程:之间不可直接共享数据,是资源的集合,进程必须有一个线程 线程:基于进程,之间可直接共享数据,可执行,只 ...

  6. Kubernetes系列之理解K8s Service的几种模式

    今天给大家介绍下k8s的service的几种访问模式. 概述 我们知道pod的ip不是固定的,是根据所在宿主机的docker0网卡生成的,每次重启,更新,调度等情况IP都会变,那pod与pod之间需要 ...

  7. 微信公众号的开发 Senparc.Weixin.dll使用

    项目需要,做个微信公众号,之前从未做过,前期挺懵的,再次记录一下,一切困难都是纸老虎(哈哈) 服务号是公司申请的微信公共账号,订阅号是个人申请的.建议开发者自己申请一个测试账号,方便使用,但是测试账号 ...

  8. scala读取配置文件

    Class: package libparser import scala.collection.mutable import scala.util.matching.Regex class conf ...

  9. BBS论坛(二十)

    20.1.cms添加轮播图后台逻辑代码完成 (1)apps/models.py from exts import db from datetime import datetime class Bann ...

  10. 多机部署redis5.0集群环境

    redis5.0集群部署 一.集群介绍 Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation). Redis 集群不支持那些需要同时处理多个键的 Redi ...