在前面的文章 HikariCP 源码分析 — ConcurrentBag 中,D瓜哥分析了一下 HikariCP 中一个非常重要的数据结构 ConcurrentBag。
今天,继续再介绍 HikariCP 中另一个很关键的数据结构: FastList。
FastList 本身的实现非常简单,要理解它的奥秘,就需要结合 Java 原生集合类的 ArrayList 来比较性地看。
构造函数 先来对比一下两者的构造函数。先来看看 FastList:
FastList public final class FastList<T> implements List<T>, RandomAccess, Serializable { private static final long serialVersionUID = -4598088075242913858L; private final Class<?> clazz; private T[] elementData; private int size; /** * Construct a FastList with a default size of 32. * @param clazz the Class stored in the collection */ @SuppressWarnings("unchecked") public FastList(Class<?
在上一篇文章 分布式锁之 Apache Curator InterProcessMutex 中介绍了基于 ZooKeeper 实现的互斥锁。除此之外,还可以实现读写锁。这篇文章就来简要介绍一下 InterProcessReadWriteLock 的实现原理。
老规矩,先看看类的注释:
/** * <p> * A re-entrant read/write mutex that works across JVMs. Uses Zookeeper to hold the lock. All processes * in all JVMs that use the same lock path will achieve an inter-process critical section. Further, this mutex is * "fair" - each user will get the mutex in the order requested (from ZK's point of view). * </p> * * <p> * A read write lock maintains a pair of associated locks, one for read-only operations and one * for writing.
对分布式锁耳熟能详。不过,一直关注的是基于 Redis 实现的分布式锁。知道 ZooKeeper 也可以实现分布式锁。但是,原来的想法是把 Redis 那个思路切换到 ZooKeeper 上来实现就好。今天了解到 Apache Curator 内置了分布式锁的实现: InterProcessMutex。查看了一下源码实现,发现跟基于 Redis 实现的源码相比,在思路上还是有很大不同的。所以,特别作文记录一下。
先来看一下,整体流程:
结合流程图和源码,加锁的过程是这样的:
先判断本地是否有锁数据,如果有则对锁定次数自增一下,然后返回 true;
如果没有锁数据,则尝试获取锁:
在指定路径下创建临时顺序节点
获取指定路径下,所有节点,检查自身是否是序号最小的节点:
如果自身序号最小,则获得锁;否则
如果自身不是序号最小的节点,则通过 while 自旋 + wait(times) 不断尝试获取锁,直到成功。
获得锁后,把锁信息缓存在本地 ConcurrentMap<Thread, LockData> threadData 变量中,方便计算重入。
在 ZooKeeper 中的结构大致如下:
下面我们逐个方法进行分析说明。先来看一下 InterProcessMutex 的注释:
/** * A re-entrant mutex that works across JVMs. Uses Zookeeper to hold the lock. All processes in all JVMs that * use the same lock path will achieve an inter-process critical section.
林纳斯·托瓦兹(Linus Torvalds)说:“我从心底认为,优秀的程序员与平庸的程序员之间的区别,是在于认为自己的代码重要还是数据结构更加重要。平庸的程序员眼里只有代码,优秀的程序员则关注数据结构及之前的关系。” 也许很多人觉得 Spring 神秘莫测,但是如果了解了它的核心数据结构,很多问题迎刃而解。
Spring 中两个数据结构最核心:① BeanDefinition,用于表示 Bean 的定义;② BeanFactory,用于表示整个 IoC 容器。
在前面文章 Spring Bean 生命周期概述中,介绍了 Spring Bean 的生命周期。不知道大家有没有思考过 Spring 在内部是如何表示一个 Bean 的?本篇文章,就来聊一聊 BeanDefinition
问题 使用 Spring 时,尤其是使用 XML 配置的时候,也许我们会这样的问题:
Bean 怎么表示?
Bean 的依赖怎么表示?
init-method 方法怎么存储?
Bean 的一些属性,比如 lazy-init 等,怎么表示?
Bean 构造函数的参数怎么存储?
…
Java 也有类似的问题,比如怎么表示一个类?Java 通过反射 API 来解决这个问题:
Class
Method
Field
Constructor
Annotation
但是,为什么 Spring 还要自己定义一套呢?主要原因是 Java 反射 API 不满足 Spring 的需求,比如,它没办法表示哪些类是 SCOPE_SINGLETON,哪些类是 SCOPE_PROTOTYPE。
另外,Spring 的 Bean 抽象也并不是完全自定义的,它是基于 Java 反射 API 又增加了自定义功能,其核心 API 就是 BeanDefinition。下面,我们来仔细看一下它的继承体系以及内部核心属性。