加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

另一种锁:ReentractLock

发布时间:2020-12-15 07:52:48 所属栏目:Java 来源:网络整理
导读:1,概述 前面我们说了volatile关键字,主要是为了处理并发读写场景,解决可见性的问题。然后又讲了synchronized锁,处理并发写的场景,解决原子性的问题。接着又说了Atomic原子系列,它是基于基本数据类型或者引用来解决原子问题,底层是基于CAS(compare an

1,概述

前面我们说了volatile关键字,主要是为了处理并发读写场景,解决可见性的问题。然后又讲了synchronized锁,处理并发写的场景,解决原子性的问题。接着又说了Atomic原子系列,它是基于基本数据类型或者引用来解决原子问题,底层是基于CAS(compare and set),无锁化(乐观锁)。这篇文章主要来说说ReentractLock,先演示一个demo,对ReentractLock有个基本的了解。

public class ReentractLockDemo {
    #获取一个lock锁
    static ReentrantLock lock = new ReentrantLock();
    #可修改的共享变量
    static volatile int flag = 0;
    public static void main(String[] args) {
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    //获取锁
                    lock.lock();
                    flag++;
                    System.out.println(Thread.currentThread().getName() + "线程修改变后的变量为" + flag);
//释放锁 lock.unlock();
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { @Override public void run() { while (true) {
//获取锁 lock.lock(); flag
++; System.out.println(Thread.currentThread().getName() + "线程修改变后的变量为" + flag);
//释放锁 lock.unlock();
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } }

?2,AQS(Abstract Queued Synchronizer)

2.1 简述

抽象队列同步器。经常听到这个词,本文就要分析下这到底是啥含义。并发包的锁都是基于AQS来实现的,一般我们开发是不直接接触的,它是并发的基础,java并发包底层的API。我们先画个图,了解下AQS的含义:

过程简述一下,当第一个线程获取锁时,将state状态+1,变成了1。此时当前加锁线程为线程1.然后线程2来获取锁,发现state不等于0,也就是有人占有了锁,此时线程2就到一个队列中排队。这时候线程3,线程N会依次来排队挂起。线程1处理任务完毕,将会唤醒队列中的线程,然后线程就去争取锁,获取到锁的线程就会出队列,重新改变state的值,将当前线程变为自己的。

?

大体过程如上所示,不过这样说起来还是太抽象了。我们从源码中去探索,看看是为啥叫AQS,队列是怎么实现的,怎么就实现了锁的功能了。。。

?

2.2 源码剖析

首先看看ReentrantLock的构造函数。

    public ReentrantLock() {
#当我们点进构造函数以后,发现里面构造了NonfairSync()对象。通过这里我们就能发现,ReentrantLock应该是一个外壳,真正执行功能的对象应该就是NonfairSync了。 sync
= new NonfairSync(); }
#我们顺势就点开NonfairSync的构造函数了。发现它也是ReentrantLock的内部类,继承自Sync对象,
static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge,backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0,1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }

通过上面的源代码,就知道了ReentrantLock里面有内部类:NonfairSync、FairSync、Sync。NonfairSync、FairSync是Sync的子类,其中NonfailSync是默认构造函数实现的(也就是非公平锁,后面会讲解它和FairSync的区别)。而且ReentrantLock就是一个外壳,真正功能的实现就是Sync这些对象。我们再看看Sync这个类,发现他是一个抽象类,继承了AbstractQueuedSynchronizer这个类。源码如下:

abstract static class Sync extends AbstractQueuedSynchronizer

?这时候发现AbstractQueuedSynchronizer。也就是我们之前说的AQS,抽象队列同步器。很明显了,核心的方法都应该在AbstractQueuedSynchronizer类里面了。来看看AbstractQueuedSynchronizer的核心的字段:

    
#这是一个指针的头部
private transient volatile Node head; #指针的尾部 private transient volatile Node tail; #状态变量state private volatile int state; #这个应该似曾相识了,之前Atomic原子系列的CAS,就是基于unsafe来实现的。这里大概也能猜测到了,ReentractLock底层是基于CAS无锁化来实现的了 private static final Unsafe unsafe = Unsafe.getUnsafe();
#下面是一些变量的内存指针。
private static final long stateOffset; private static final long headOffset; private static final long tailOffset; private static final long waitStatusOffset; private static final long nextOffset;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读