一、介绍
ReentrantLock是一种独占锁,同一时刻下锁只能被一个线程拥有,其他竞争锁的线程必须排队等待。
ReentrantLock是基于AbstractQueuedSynchronizer(AQS)来实现的。AQS维护了一个双向链表,这个双向链表存储了排队等待锁的线程,每个等待锁的线程对应一个节点Node.
ReentrantLock也是Java中常用的锁,属于乐观锁类型,多线程并发情况下,能保证共享数据安全性,线程间有序性。
ReentrantLock通过原子操作和阻塞实现锁原理,一般使用lock获取锁,unlock释放锁;
下面说一下锁的基本使用和底层基本实现原理,lock和unlock底层
lock的时候可能被其他线程获得所,那么此线程会阻塞自己,关键原理底层用到Unsafe类的API: CAS和park
二、ReentrantLock 特征
(1)可实现中断等待 : 当一个线程迟迟等不到锁时,可以中断等待,不等了,去做其他的事。
lockInterruptibly ->获取锁,跟lock不一样的地方是,过程中会检测是否中断 (interrupt),若是会抛出异常
(2)可实现公平锁和非公平锁两种方式,默认是使用非公平锁。通过构造函数new ReentrantLock(true)可以实现公平锁。
非公平锁模式下,线程竞争锁时先做CAS操作,如果当前state为0并且竞争锁线程成功将state设置为1,那线程就占有了锁。否则,执行acquire方法。
公平锁模式下,如果有线程竞争锁,直接执行acquire()方法。
(3)锁可绑定多个条件。
三 、使用
测试代码 如下 :
import java.util.concurrent.atomic.AtomicInteger;
/***
* 使用 ReentrantLock 多个condition 控制两个线程交替执行
*/
public class ReentrantLockTest {
/** 交替打印次数 **/
private static volatile AtomicInteger times = new AtomicInteger(100);
/** 线程A是否开始运行 **/
private static volatile boolean flag = false;
public static void main(String[] args) {
final PrintObject printObject = new PrintObject();
Thread t1 = new Thread(()->{
flag = true;
while(times.getAndDecrement()>0){
printObject.printA();
}
});
t1.start();
while(true){
if(flag){
Thread t2 = new Thread(()->{
while(times.getAndDecrement()>0){
printObject.printB();
}
});
t2.start();
break;
}
}
while(times.get()>0){
//do noting ......
}
System.out.println("\n程序结束........");
System.exit(0);
}
}