之前已经花了大量时间分析同步器框架AQS
的源码实现,这篇文章分析一下CountDownLatch
的源码实现,本文参看的JDK
源码为JDK11
,其他版本不一定适合。
CountDownLatch其实是复合名词,由单词countdown和latch复合而来。countdown是倒数的意思,而latch则是闩锁、闭锁的意思,复合词容易让人联想到预先设定一个计数值,并且"锁住(阻塞)“一些东西(线程),然后进行倒数,当数值减少到0的时候进行"放行(解除阻塞)”。
CountDownLatch
是AQS共享模式下的典型实现。本文会先简单介绍CountDownLatch
的基本API
、类比监视器方式的实现以及深入分析其源码实现。
很早之前就打算看一次JUC线程池ThreadPoolExecutor
的源码实现,由于近段时间比较忙,一直没有时间整理出源码分析的文章。之前在分析扩展线程池实现可回调的Future
时候曾经提到并发大师Doug Lea
在设计线程池ThreadPoolExecutor
的提交任务的顶层接口Executor
只有一个无状态的执行方法:
public interface Executor {
void execute(Runnable command);
}
而ExecutorService
提供了很多扩展方法底层基本上是基于Executor#execute()
方法进行扩展。本文着重分析ThreadPoolExecutor#execute()
的实现,笔者会从实现原理、源码实现等角度结合简化例子进行详细的分析。ThreadPoolExecutor
的源码从JDK8
到JDK11
基本没有变化,本文编写的时候使用的是JDK11
。
并发编程大师Doug Lea在编写JUC
(java.util.concurrent
)包的时候引入了java.util.concurrent.locks.AbstractQueuedSynchronizer
,其实是Abstract Queued Synchronizer
,也就是"基于队列实现的抽象同步器",一般我们称之为AQS
。其实Doug Lea
大神编写AQS
是有严谨的理论基础的,他的个人博客上有一篇论文《The java.util.concurrent Synchronizer Framewor》,可以在互联网找到相应的译文《JUC同步器框架》,如果想要深入研究AQS
必须要理解一下该论文的内容,然后结合论文内容详细分析一下AQS
的源码实现。本文在阅读AQS
源码的时候选用的JDK
版本是JDK11
。
出于写作习惯,下文会把AbstractQueuedSynchronizer称为AQS、JUC同步器框或者同步器框架。
最近有点懒散,没什么比较有深度的产出。刚好想重新研读一下JUC
线程池的源码实现,在此之前先深入了解一下Java
中的线程实现,包括线程的生命周期、状态切换以及线程的上下文切换等等。编写本文的时候,使用的JDK
版本是11。
最近一两个月花了很大的功夫做UCloud
服务和中间件迁移到阿里云的工作,没什么空闲时间撸文。想起很早之前写过ThreadLocal
的源码分析相关文章,里面提到了ThreadLocal
存在一个不能向预先创建的线程中进行变量传递的局限性,刚好有一位HSBC
的技术大牛前同事提到了团队引入了transmittable-thread-local解决了此问题。借着这个契机,顺便clone
了transmittable-thread-local
源码进行分析,这篇文章会把ThreadLocal
和InheritableThreadLocal
的局限性分析完毕,并且从一些基本原理以及设计模式的运用分析transmittable-thread-local
(下文简称为TTL
)整套框架的实现。
如果对线程池和ThreadLocal
不熟悉的话,可以先参看一下前置文章:
这篇文章前后花了两周时间编写,行文比价干硬,文字比较多(接近5W
字),希望带着耐心阅读。
今天(2020-01-18
)在编写Netty
相关代码的时候,从Netty
源码中的ThreadDeathWatcher
和GlobalEventExecutor
追溯到两个和线程上下文类加载器ContextClassLoader
内存泄漏相关的Issue
:
两个Issue
分别是两位前辈在2017-12
的时候提出的,描述的是同一类问题,最后被Netty
的负责人采纳,并且修复了对应的问题从而关闭了Issue
。这里基于这两个Issue
描述的内容,对ContextClassLoader
内存泄漏隐患做一次复盘。
之前的一篇文章JUC线程池ThreadPoolExecutor源码分析深入分析了JUC线程池的源码实现,特别对Executor#execute()
接口的实现做了行级别的源码分析。这篇文章主要分析一下线程池扩展服务ExecutorService
接口的实现源码,同时会重点分析Future
的底层实现。ThreadPoolExecutor
和其抽象父类AbstractExecutorService
的源码从JDK8到JDK11基本没有变化,本文编写的时候使用的是JDK11,由于ExecutorService
接口的定义在JDK[8,11]都没有变化,本文的分析适用于这个JDK版本范围的任意版本。最近尝试找Hexo
可以渲染Asciidoc
的插件,但是没有找到,于是就先移植了Asciidoc
中的五种Tip
。
最近在看JUC线程池java.util.concurrent.ThreadPoolExecutor
的源码实现,其中了解到java.util.concurrent.Future
的实现原理。从目前java.util.concurrent.Future
的实现来看,虽然实现了异步提交任务,但是任务结果的获取过程需要主动调用Future#get()
或者Future#get(long timeout, TimeUnit unit)
,而前者是阻塞的,后者在异步任务执行时间不确定的情况下有可能需要进行轮询,这两种情况和异步调用的初衷有点相违背。于是笔者想结合目前了解到的Future
实现原理的前提下扩展出支持(监听)回调的Future
,思路上参考了Guava
增强的ListenableFuture
。本文编写的时候使用的JDK是JDK11,代码可以在JDK[8,12]版本上运行,其他版本可能不适合。
今天下班时候和同事聊天偶然听到面试题“两个线程交替打印奇数和偶数”的实现,这里做一个复盘。
前段时间花了大量时间去研读JUC中同步器AbstractQueuedSynchronizer
的源码实现,再结合很久之前看过的一篇关于Object
提供的等待和唤醒机制的JVM实现,发现两者有不少的关联,于是决定重新研读一下Object
中提供的阻塞和唤醒方法。本文阅读JDK类库源码使用的JDK版本是JDK11,因为本文内容可能不适合于其他版本。
1 / 2