Java并发研究 自己写ReentrantLock和ReentrantReadWriteLock(3)

本系列是基于经验设计原型,然后不断优化最终达到和AQS(AbstractQueuedSynchronizer)类似的设计。最终结果不一定和AQS完全一致,基于个人理解会有修改,可以作为理解AQS的不完全参考。

上篇。本篇主要介绍Condition即条件变量的实现,ReentrantLock中最后一块需要实现的内容。

在实现条件变量之前,考虑一下条件变量的一些特性。

  1. 条件变量依赖锁,而且是独占锁
  2. 执行await方法后释放锁,当前线程进入睡眠状态,等待满足条件后被其他线程signal/signalAll唤醒,被唤醒后会尝试重新获取锁
  3. 唤醒可以选择一个也可以全部

注意第一条特性,条件变量依赖的是独占锁,所以类似读锁这种共享锁是不支持条件变量的,ReentrantReadWriteLock中ReadLock#newCondition的实现是直接抛错。

按照第二条特性,可以得到如下的执行过程

Read More

Java并发研究 自己写ReentrantLock和ReentrantReadWriteLock(2)

接着上篇,本篇主要介绍如何添加限时tryLock方法。介绍完之后,ReentrantLock除了condition之外都会实现,而且基本和实际ReentrantLock代码接近。上篇也提到过,实际ReentrantLock依赖AQS,但是本文不会直接介绍AQS,只是AQS的一个不完全分析。

顺便提一下,“自己写ReentrantLock和ReentrantReadWriteLock”由于篇幅比较长,预计会分成3到4篇左右。

在进入限时tryLock方法的介绍之前,考虑一个问题:上篇中FairLock1和UnfairLock1是否可以复用Node?

为什么要问这个问题?因为C++代码比较关注对象的生命周期。使用C++实现锁的话必须关注何时可以回收Node的内存。如果你了解CLHLock的话,可以知道CLHLock是可以复用Node的,最多是N个(线程)+1个(哨兵)Node,理论上不需要回收。所以和CLHLock基本一致的FairLock1,同样可以用类似CLHLock的方式,即复用前序节点为自己的当前节点(CLHLock是复用前序节点的,至于为什么可以参阅CLHLock的介绍)。UnfairLock1中由于可能是非公平模式,不知道前序节点是谁,也就无法简单复用了。

Read More

Java并发研究 自己写ReentrantLock和ReentrantReadWriteLock(1)

最近个人在研究如何实现Transaction Memory,这其实也是受《the art of multiprocessor programming》最后一章的影响。作为研究的一部分,个人需要一个类似ReadWriteLock语义的同步器,于是分析了一下现有ReentrantLock和ReentrantReadWriteLock。在分析之前我其实知道ReentrantLock和ReentrantReadWriteLock都是基于AbstractQueuedSynchronizer,所以本篇也可以作为AbstractQueuedSynchronizer的不完全分析。

首先从ReentrantLock开始分析。最简单的不公平模式,无等待(SPIN,PARK)的锁。

Read More

XnnYygn的2018年小结

如果没记错的话,这次是自己第一次写年度小结。为什么突然想写小结?可能主要是因为自己觉得在2018年里技术有比较大的进步吧。

2018年上半年抱着自己实现一个MQ的想法,空闲时间收集相关资料,学习Netty,每天看看《开发者头条》。

2018年中期,Netty学得差不多了,决定在实现MQ之前,找一个东西练手,结果把Raft实现了一遍。虽然不够完美,但是第一次接触了分布式领域的论文。之后又阅读了GOSSIP相关论文,基于自己的理解,实现了基于GOSSIP的集群管理(动态加入和退出)。

如果对上述代码有兴趣,欢迎到github上阅读和关注。

https://github.com/xnnyygn/xraft

https://github.com/xnnyygn/xgossip

代码开发中,觉得自己的并发编程技术有所欠缺,在寻找并发编程资料时,发现了《the art of multiprocessor programming》。这本书绝对是我从学编程开始找到的最好的一本书。开始看了之后就一发不可收拾,花了几个月看完第一遍之后,现在看第二遍中。最近每周一篇的Java并发库的分析,之后有机会的话准备写一本《如何自己写并发库》相关的书。

Read More