CountDownLatch 是一个同步辅助工具,用于阻塞当前一个或多个线程以等待其它线程中的操作完成。在构造 CountDownLatch 对象时,我们需要指定一个非负的 count 值,一般情况下,调用 CountDownLatch#await
方法的线程需要阻塞等待该 count 值变为 0 时才能够继续往下执行。具体示例可以参考 理清 CountDownLatch 与 CyclicBarrier 的区别。
深入理解 JUC:ReentrantReadWriteLock
上一篇我们分析了 ReentrantLock 锁的设计与实现,对于大部分并发场景来说已经能够满足同步加锁的需求,但是相对于本文将要介绍的 ReentrantReadWriteLock 锁而言,ReentrantLock 主要存在的不足在于不区分读操作和写操作。考虑读多写少的场景,如果将读操作和写操作一视同仁的对待,那么线程之间读操作是互斥的,同一时间只允许一个线程读取数据,势必会影响系统的吞吐性能,并且读操作并不会导致数据的不一致性,这种情况下应该允许多个线程对同一份数据执行并发读取。
深入理解 JUC:ReentrantLock
上一遍我们深入分析了 AQS 的设计与实现,了解到 AQS 是 JUC 包实现的基础支撑,本文我们就来分析一个基于 AQS 实现的 JUC 组件,即 ReentrantLock。
ReentrantLock 译为可重入锁,我们在使用时总是将其与 synchronized 关键字进行对比,实际上 ReentrantLock 与 synchronized 关键字在使用上具备相同的语义,区别仅在于 ReentrantLock 相对于 synchronized 关键字留给开发者的可操作性更强,所以在使用上更加灵活,当然凡事都有两面,灵活的背后也暗藏着更加容易出错的风险。
深入理解 JUC:AQS 队列同步器
AbstractQueuedSynchronizer 简称 AQS,可能我们几乎不会直接去使用它,但它却是 JUC 的核心基础组件,支撑着 java 锁和同步器的实现,例如 ReentrantLock、ReentrantReadWriteLock、CountDownLatch,以及 Semaphore 等。大神 Doug Lea 在设计 JUC 包时希望能够抽象一个基础且通用的组件以支撑上层模块的实现,AQS 应运而生。
AQS 本质上是一个 FIFO 的双向队列,线程被包装成结点的形式,基于自旋机制在队列中等待获取资源(这里的资源可以简单理解为对象锁)。AQS 在设计上实现了两类队列,即 同步队列 和 条件队列 ,其中同步队列服务于线程阻塞等待获取资源,而条件队列则服务于线程因某个条件不满足而进入等待状态。条件队列中的线程实际上已经获取到了资源,但是没有能够继续执行下去的条件,所以被打入条件队列并释放持有的资源,以让渡其它线程执行,如果未来某个时刻条件得以满足,则该线程会被从条件队列转移到同步队列,继续参与竞争资源,以继续向下执行。
深入理解 JUC:synchronized 关键字
关键字 synchronized 是 java 程序员在进入并发编程世界时的银弹,只要是遇到有并发访问安全的地方,会无脑的加上一个 synchronized 关键字进行修饰。但是随着对 java 并发编程的逐渐深入,我们也开始慢慢意识到 synchronized 是一个重量级的操作,曾经甚至有一段时间人们倡导使用 Lock 来代替 synchronized 关键字。不过 Lock 虽然灵活但也有其弊端,对开发人员写出线程安全且无死锁的多线程程序要求相对要提高了许多,好在 java 6 对 synchronized 关键字进行了大刀阔斧的优化,并推荐在 Lock 和 synchronized 均满足需求的场景下优先使用 synchronized 关键字。本文我们就一起来深入分析一下 synchronized 关键字的实现内幕。
Scala 集合:Map API
Map 定义了键值对的特质类型,区分可变与不可变,间接继承了偏函数 PartialFunction 特质,所以一个 Map 本质上也是一个偏函数,其定义如下:
1 | trait Map[K, +V] extends Iterable[(K, V)] with GenMap[K, V] with MapLike[K, V, Map[K, V]] |
其伴生对象提供了构造 Map 对象的简单方式,示例:
1 | val map1 = Map("name" -> "zhenchao", "age" -> 28) |
Scala 集合:Set API
Set 用于表示一个不包含重复元素的集合,不强调元素的顺序性。Set 同样被定义为是一个特质类型,区分可变与不可变,定义如下:
1 | trait Set[A] extends (A => Boolean) |
Scala 集合:Seq API
Seq 是一个特质类型(定义如下),用于表示按照一定顺序排列的元素序列,Seq 继承了偏函数 PartialFunction 特质,所以一个序列本质上也是一个偏函数,对应的函数类型是 Int => A
,其中 A 是对应 Seq 的元素类型,而输入参数是 Seq 的下标。
1 | trait Seq[+A] extends PartialFunction[Int, A] |
Scala 集合:基础 API
Traversable 和 Iterable 特质定义了 scala 集合的基本操作,后续文章中将要介绍的 Seq、Set,以及 Map 等集合都实现了这两个特质。本文主要对 Traversable 和 Iterable 中定义的方法进行归类和介绍,了解这些方法也就基本知道了 scala 集合的大部分操作。
Traversable 定义为 Trait 类型,包含 2 个直接派生的子特质 mutable.Traversable
和 immutable.Traversable
,分别表示可变集合和不可变集合。其中不可变集合是指集合中的元素一旦初始化完成便不可再被修改,任何对该集合的修改操作都将生成一个新的集合。Traversable 特质的定义如下:
1 | trait Traversable[+A] extends TraversableLike[A, Traversable[A]] |
那些年,面试被虐过的红黑树
- 面试官 :小桂子是吧,看你简历上写着精通 java 编程,想必对 java 已经掌握的很好了吧?
- 小桂子 :系呀系呀,一直都用 java 写 bug 呢~
- 面试官 :那你说说 jdk1.7 之前 HashMap 的底层实现原理呗,另外为什么在高并发场景下可能造成较高的 CPU 占用?
- 小桂子 :这个。。。好像是红黑树?
- 面试官 :哦?你说的是 jdk1.8 之后的设计,既然你提到了,那就聊聊红黑树这个数据结构吧,这里是白纸和笔,手写一棵吧!
- 小桂子 :哎呀,哎呀哎呀,老师,突然肚子好疼,我要去一下厕所,一会儿就回来~~~