参考:https://www.cnblogs.com/takumicx/p/9338983.html
ReentrantLock可重入锁:jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock。虽然在性能上ReentrantLock和synchronized没有什么区别,但ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。
1、ReentrantLock和synchronized都是独占锁,只允许线程互斥的访问临界区。但是实现上两者不同:synchronized加锁解锁的过程是隐式的,用户不用手动操作,优点是操作简单,但显得不够灵活。一般并发场景使用synchronized的就够了;ReentrantLock需要手动加锁和解锁,且解锁的操作尽量要放在finally代码块中,保证线程正确释放锁。ReentrantLock操作较为复杂,但是因为可以手动控制加锁和解锁过程,在复杂的并发场景中能派上用场。
2、ReentrantLock和synchronized都是可重入的。synchronized因为可重入因此可以放在被递归执行的方法上,且不用担心线程最后能否正确释放锁;而ReentrantLock在重入时要却确保重复获取锁的次数必须和重复释放锁的次数一样,否则可能导致其他线程无法获得该锁。
不使用ReentrantLock锁的情况:
// 不使用锁
public class Demo09 implements Runnable { public static ReentrantLock lock = new ReentrantLock(); //锁 相当于一份公共资源 public static void main(String[] args) { Thread t1 = new Thread(new Demo09()); Thread t2 = new Thread(new Demo09()); t1.start(); t2.start(); } @Override public void run() { // lock.lock(); // 获取锁 for(int j = 0; j < 3; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } // lock.unlock(); // 释放锁 } }
结果:
使用ReentrantLock:
public class Demo09 implements Runnable { public static ReentrantLock lock = new ReentrantLock(); //锁 相当于一份公共资源 public static void main(String[] args) { Thread t1 = new Thread(new Demo09()); Thread t2 = new Thread(new Demo09()); t1.start(); t2.start(); } @Override public void run() { lock.lock(); // 获取锁 for(int j = 0; j < 3; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } lock.unlock(); // 释放锁 } }
结果:
源码分析:
首先看构造函数:
/** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); } /** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
默认创建一个非公平锁,如果传入参数为true即创建一个公平锁,然后获取一个Sync对象(公平锁与非公平锁https://www.cnblogs.com/DDiamondd/p/11316393.html)
abstract static class Sync extends AbstractQueuedSynchronizer {}
Sync类继承了AbstractQueuedSynchronizer (AQS 抽象队列同步器,定义了一套多线程访问共享资源的同步器框架)
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {}
AbstractQueuedSynchronizer类里面有两个非常重要的参数:
1)state:当前锁的状态,初始值为0。 当某个线程获取一次该锁state就+1, 释放一次该锁state就-1,也只有当state=0时,其他线程才有机会获取锁
2)exclusiveOwnerThread: 获取锁的线程 这个属性是继承于 AbstractOwnableSynchronizer类,因为ReentrantLock是独占锁,当然需要一个属性来记录获取该锁的线程