在java.util.locks包下面提供了三种锁,ReentrantLock、ReentrantReadWriteLock和StampedLock,下面一一讲解这三种锁的特点、实现方式以及应用。
通用方法讲解
这三种锁都实现了lock接口,先解读一下Lock接口的方法及含义:
void lock(); 方法,阻塞方法,直到可以获取到锁;
void lockInterruptibly()方法,阻塞方法,直到可以获取到锁或者被其他线程中断;
boolean tryLock();尝试获取锁,获取不到立刻返回
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;尝试获取锁,直到超时;
void unlock();解锁操作
newCondition()方法;实现等待、通知模式,后面例子中会讲解其应用
ReentrantLock
reentrantLock可以实现synchronized的所有功能,并且扩展了更丰富的功能;
reentrant的中文含义是:可重入的意思,也就是它是可重入锁;支持公平锁和非公平锁两种方式支持获取不到锁,可以被中断支持超时设置
reentrantLock 与 syn对比
经典的使用方式如下:
lock的使用方式
加锁之后使用try-finally进行逻辑处理与锁的释放。
lock加锁操作会使得HoldCount计数加1,每一个lock都需要对应一个unlock,即便是在同一个线程中,如果调用了两次lock,需要调用两次unlock才能完全释放锁,否则的话,其
他线程是获取不到锁的。
reentrantLock是基于CAS+AQS框架实现的,具体原理在AQS框架章节会讲到;
{!-- PGC_COLUMN --}ReentrantReadWriteLock
ReentrantReadWriteLock实现了读写锁,所谓的读写锁实际上是一对锁,一个是读锁、另一个是写锁;如果写锁没有加锁的话,读锁可以被多个线程持有;而写锁与写锁、写锁与读锁之间是互斥的,只能有一个线程持有;
上面是英文直译,说白一点就是可以多线程同时读数据,一旦有线程写数据,那就其他线程既不能读,也不能写;
通常需要用到线程安全的Map时,我们一般会用HashTable或ConcurrentHashMap;但其实利用HashMap + 读写锁也可以实现,效率比HashTable好。
读写锁
StampedLock
stampedLock是JDK8新增的一个锁,这个锁是不可重入的;重入的话会造成死锁。
这个锁主要利用乐观锁机制来优化读写锁的性能,我们知道,对于ReentrantReadWriteLock,在加了读锁的情况下,会阻塞写操作。
stampedLock可以在加了读锁的情况下不阻塞写操作,也就是其他线程依然可以获取写锁。
可以通过validate方法校验加乐观锁之后,数据有没有被修改;
具体用法如下:
乐观锁
第151行加乐观读锁,第152行读数据;第153行校验加乐观读锁到读取数据完成期间,数据有没有被改变,如果被改变的话,则使用悲观读锁再次进行读,如果没有被改变,则直接返回结果。
感谢您的阅读,如有疑问,欢迎留言评论; 如果觉得读完有所收获,请收藏点赞转发~