什么是设计模式

在GoF(Gang of Four)的书籍《Design Patterns - Elements of Reusable Object-Oriented Software(设计模式-可复用面向对象软件的基础)》中是这样定义设计模式的:Christopher Alexander说过:“每一个模式描述了一个在我们周围不断重复发生的问题以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动” [AIS+77,第10页]。尽管Alexander所指的是城市和建筑模式,但他的思想也同样适用于面向对象设计模式,只是在面向对象的解决方案里, 我们用对象和接口代替了墙壁和门窗。两类模式的核心都在于提供了相关问题的解决方案。一般而言,设计模式有四个基本要素:

  1. 模式名称(pattern name):一个助记名,它用一两个词来描述模式的问题、解决方案和效果。
  2. 问题(problem):描述了应该在何时使用模式。
  3. 解决方案(solution):描述了设计的组成成分,它们之间的相关关系以及各自的职责和协作方案。
  4. 效果(consequences):描述了模式应用的效果以及使用模式应该权衡的问题。

设计模式的创始人很明确地指出了设计模式的基本要素,但是由于现实中浮躁、偏向过度设计等因素的干扰,开发者很多时候会重点关注第1和第3点要素(过度关注设计模式和设计模式的实现),忽略第2和第4点要素(忽视使用设计模式的场景和目标),导致设计出来的编码逻辑可能过于复杂或者达不到预期的效果。

总的来说,设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。也就是本来并不存在所谓设计模式,用的人多了,也便成了设计模式。

前提

Doug Lea大神在编写JUC(java.util.concurrent)包的时候引入了java.util.concurrent.locks.AbstractQueuedSynchronizer,Abstract Queued Synchronizer,也就是”基于队列实现的抽象同步器”,一般我们称之为AQS。其实Doug Lea大神编写AQS是有严谨的理论基础的,他的个人博客上有一篇论文《The java.util.concurrent Synchronizer Framework》,文章在http://ifeve.com上可以找到相关的译文(《JUC同步器框架》),如果想要深入研究AQS必须要理解一下该论文的内容,然后详细分析一下AQS的源码实现。本文在阅读AQS源码的时候选用的JDK版本是JDK11。

AQS的主要功能

AQS是JUC包中用于构建锁或者其他同步组件(信号量、事件等)的基础框架类。AQS从它的实现上看主要提供了下面的功能:

  • 同步状态的原子性管理。
  • 线程的阻塞和解除阻塞。
  • 提供阻塞线程的存储队列。

基于这三大功能,衍生出下面的附加功能:

  • 通过中断实现的任务取消,基于线程中断实现。
  • 可选的超时设置,也就是调用者可以选择放弃等待。
  • 定义了Condition接口,用于支持管程形式的await/signal/signalAll操作,代替了Object类基于JNI提供的wait/notify/notifyAll。

AQS还根据同步状态的不同管理方式区分为两种不同的实现:独占状态的同步器共享状态的同步器

前提

最近接触到的一个项目要兼容新老系统,最终采用了ThreadLocal(实际上用的是InheritableThreadLocal)用于在子线程获取父线程中共享的变量。问题是解决了,但是后来发现对ThreadLocal的理解不够深入,于是顺便把它的源码阅读理解了一遍。在谈到ThreadLocal之前先买个关子,先谈谈黄金分割数。本文在阅读ThreadLocal源码的时候是使用JDK8(1.8.0_181)。