前言在多线程开发中,为了控制线程同步,使用最多的关键字是synchronized和reentrantlocks。在JDK8中,引入了一种新武器StampedLock。这是什么?英文单词Stamp的意思是邮戳。那么这里用什么意思呢?傻瓜,请看下面的细分。面对临界区的资源管理问题,一般有两套思路:第一是采用悲观策略。悲观者认为每次访问临界区的共享变量,总会有人跟我发生冲突。因此,每次对于每次访问我都必须锁定整个对象并在访问后解锁它。相反,乐观主义者认为,虽然临界区中的共享变量会发生冲突,但冲突应该是小概率事件。在大多数情况下,它不应该发生。因此,我可以先参观一下。如果我使用的数据没有冲突,那么我的操作就成功了;如果我用完之后发现有人冲突,那么我要么再试一次,要么转为悲观策略。从这里不难看出,可重入锁和synchronized是典型的悲观策略。聪明的你一定猜到了,StampedLock是一个提供乐观锁的工具,所以它是可重入锁的重要补充。StampedLock的基本使用在StampedLock的文档中提供了一个很好的例子,让我们可以快速的了解StampedLock的使用。下面我来看看这个例子,它的描述写在评论里。这里再解释一下validate()方法的含义。函数签名如下所示:publicbooleanvalidate(longstamp)它接受的参数是上次锁定操作返回的邮票。如果锁在调用validate()之前没有申请过写锁,那么它返回true,这也意味着被锁保护的共享数据没有被修改,所以前面的读操作肯定能保证数据的完整性和一致性。反之,如果锁在validate()之前有成功的写锁申请,说明之前的数据读写操作发生冲突,程序需要重试,或者升级为悲观锁。与可重入锁相比,从上面的例子不难看出。在编程复杂度上,StampedLock其实比可重入锁要复杂很多,代码也没有以前那么简洁了。那么,为什么我们仍然使用它呢?最本质的原因是为了提高性能!一般来说,这种乐观锁的性能要比普通的可重入锁快数倍,而且随着线程数的不断增加,性能上的差距会越来越大。总之,StampedLock的性能在大量并发场景下碾压可重入锁和读写锁。但毕竟世界上没有完美的东西,StampedLock也不是万能的。它的缺点如下:编码比较麻烦。如果使用乐观阅读,那么冲突的场景必须由应用程序自己处理。它不可重入。在一个线程中调用两次,您的世界就干净了。....它不支持等待/通知机制。如果以上3点对你来说都不是问题,那么相信StampedLock应该是你的首选。内部数据结构为了帮助大家更好的理解StampedLock,这里简单介绍一下它的内部实现和数据结构。在StampedLock中,有一个队列存放等待锁的线程。队列是一个链表,链表中的元素是一个叫做WNode的对象:当队列中有多个线程在等待时,整个队列可能是这样的:除了这个等待队列,StampedLock中还有一个特别重要的字段是longstate,是一个64位整数,StampedLock用的很巧妙。state的初始值为:privatestaticfinalintLG_READERS=7;privatestaticfinallongWBIT=1L<
