首页 > 其他分享 >ReadWriteLock的简单分析

ReadWriteLock的简单分析

时间:2023-10-29 17:44:38浏览次数:27  
标签:分析 ReentrantReadWriteLock ReadWriteLock 简单 final 读锁 线程 lock public

ReentrantReadWriteLock是jdk中提供的一种相比于ReentrantLock能提供更高的读效率的锁

一、基本使用

public static void main(String[] args) throws InterruptedException {

        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        //获取读锁
        ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
        //获取写锁
        ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //用读锁对象读锁
                    readLock.lock();
                    log.info("加读锁成功");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    readLock.unlock();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //用写锁对象加写锁
                    writeLock.lock();
                    log.info("加写锁成功");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    writeLock.unlock();
                }
            }
        });
        t1.start();
        t2.start();

    }

虽然加读锁和写锁用了2个锁对象,但它们都使用的ReentrantReadWriteLock中的同一个同步器对象。

二、特点

相比于ReentrantLock ,它支持读读操作的并发,即可以支持多个线程的同时读,但读写操作之间还是会被阻塞住。

进行读操作就要加读锁,调用readerLock对象的lock方法,写操作加写锁,调用writerLock对象的lock方法。

持有读锁时再次重入要加写锁(锁升级) 这种是不支持的,会一直等待,

持有写锁时再次重入要加读锁(锁降级) 这种是支持的。

三、原理分析

相比于ReentrantLock,ReentrantReadWriteLock 中的state低8为表示写锁的加锁状态,高8为表示读锁的加锁状态。

3.1 构造方法

先看写构造方法

public class ReentrantReadWriteLock
    implements ReadWriteLock, java.io.Serializable {
    // 加读锁和写锁时分别使用这2个内部类的对象来操作
    private final ReentrantReadWriteLock.ReadLock readerLock;
    /** Inner class providing writelock */
    private final ReentrantReadWriteLock.WriteLock writerLock;
    /** Performs all synchronization mechanics */
    final Sync sync;
    /**
     * Creates a new {@code ReentrantReadWriteLock} with
     * default (nonfair) ordering properties.
     */
    public ReentrantReadWriteLock() {
        this(false);
    }

   //也分了公平锁和非公平锁的情况
    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }
	//获取读锁/写锁对象的方法
    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
}

3.2 加锁流程

加写锁会调用写锁对象的lock方法,加读锁会调用读锁对象的lock方法

public class ReentrantReadWriteLock
    implements ReadWriteLock, java.io.Serializable {
    //写锁对象内部类
    public static class WriteLock implements Lock, java.io.Serializable {
        private final Sync sync;
        
        protected WriteLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }
        
        public void lock() {
            //可以看到这个lock方法直接调用了aqs中的acquire方法
            //尝试加锁的tryAcquire会在ReentrantReadWriteLock中的同步器子类中实现,
            sync.acquire(1);
        }
    }
    
    //读锁对象内部类
    public static class ReadLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -5992448646407690164L;
        private final Sync sync;
        
        protected ReadLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }
        
        //这是加读锁的方法,lock方法调用aqs中的acquireShared方法,具体逻辑需要看aqs中的实现
        public void lock() {
            sync.acquireShared(1);
        }
    }
    
    //同步器实现类
    abstract static class Sync extends AbstractQueuedSynchronizer {
        
           //这是加写锁的实现
           protected final boolean tryAcquire(int acquires) {
                    
            Thread current = Thread.currentThread();
            int c = getState();
            //这个方法返回state低8为的值即写锁部分的值
            int w = exclusiveCount(c);
            //c不等于0表示这个同步器别的线程已经加过锁了
            if (c != 0) {
                // w=0表示已经加的是读锁,如果owner不是当前线程就要返回加锁失败
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                //走到这里表示w!=0且owner是当前线程,即发生了锁重入
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                //修改state,返回true
                setState(c + acquires);
                return true;
            }
            //如果c=0会走到这里, writerShouldBlock是个抽象方法,在非公平锁的实现中会返回false,
            //就继续执行后边的compareAndSetState,如果成功了表示加锁成功,失败了就返回false表示加锁
            //失败,在公平锁的实现中writerShouldBlock会根据当前阻塞队列中是否已经有等待的线程来决定
            //返回值。
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }
        
        //加读锁公平模式时会调用到的方法
        protected final int tryAcquireShared(int unused) {
            Thread current = Thread.currentThread();
            int c = getState();
            //如果获取到state低八位的值不是0表示当前有写锁,锁降级不被允许所以返回加锁失败
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            //走到这里表示没有写锁
            //获取读锁的状态值
            int r = sharedCount(c);
            // readerShouldBlock方法是用来处理公平锁的,在公平/非公平两个内部类中有不同的实现,
            //公平实现中会看当前队列中有没有在等待的读锁,
            //如果有当前线程就不去抢锁了.
            //非公平实现中直接返回true,当前线程会去抢锁。
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                if (r == 0) {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
                    firstReaderHoldCount++;
                } else {
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current))
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;
                }
                return 1;
            }
            return fullTryAcquireShared(current);
        }
    }
}

aqs部分源码

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
    public final void acquire(int arg) {
    	//其中tryAcquire由子类实现,acquireQueued把线程加入阻塞队列等待
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
    //加读锁的方法
    public final void acquireShared(int arg) {
    	// tryAcquireShared方法由子类来实现,返回小于0的数表示加锁失败,才需要执行后续逻辑
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
    
    
    //加读锁的方法
    private void doAcquireShared(int arg) {
    	//创建读锁等待节点
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
            	//获取当前节点的前一个节点
                final Node p = node.predecessor();
                if (p == head) {
                	//这块是读线程被唤醒后执行的操作,继续抢锁
                    int r = tryAcquireShared(arg);
                    //这个r大于0表示当前有多个线程在等待读锁,
                    //进if后 setHeadAndPropagate 判断下下一个节点是不是也在等待读锁,如果是把它也唤醒
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//这个方法让当前线程阻塞
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
}

至于解锁流程比较简单就不具体分析了。

标签:分析,ReentrantReadWriteLock,ReadWriteLock,简单,final,读锁,线程,lock,public
From: https://www.cnblogs.com/chengxuxiaoyuan/p/17796098.html

相关文章

  • spring aot分析
    native-imagegraalvm支持使用native-image工具来生成二进制可执行文件。对于运行时反射需要使用agent在运行时收集元信息,即META-INF/native-image/xxx/*.json文件。通过agent收集元数据的文章:https://www.graalvm.org/reference-manual/native-image/guides/configure-with-tra......
  • 简单c++构建第一人称
    本文内容为UE4.27的文档教程GameMode确定新建的项目会自动生成GameMode,如果有更改,而不是使用默认的GameMode类,就需要在引擎的设置中更改角色的实现前后左右移动//前后MoveForwardvoidAFPSCharacter::MoveForward(floatvalue){ //利用控制器方向寻找前进的方向就是角色......
  • 【C++】继承 ⑬ ( 虚继承原理 | 虚继承解决继承二义性问题 | 二义性产生的原因分析 )
    文章目录一、虚继承原理1、虚继承解决继承二义性问题2、二义性产生的原因分析3、虚继承原理二、代码示例-虚继承原理1、完整代码示例2、执行结果一、虚继承原理1、虚继承解决继承二义性问题继承的二义性:如果一个子类(派生类)继承多个父类(基类),这些父类都继......
  • 第 369 场周赛(简单位运算,分类讨论,dfs,树形dp)
     简单位运算模拟classSolution{public:intfindKOr(vector<int>&nums,intk){vector<int>bit(32,0);for(inti=0;i<31;i++){intcnt=0;for(autox:nums){if(x>>......
  • 转岗项目经理后,我是如何分析需求的
    项目经理有一项工作就是需求分析,需求的本质是根据认知进行假设,然后给出判断。如果需求分析的结果出了问题,那么产品也必然会失败。本文针对如何进行需求分析展开分析,希望能对你有所启发。一、什么是需求为什么要明确需求的定义,因为需求很容易被误解。在这里我们要区分下用户需求和产......
  • 转岗项目经理后,我是如何做竞品分析的
    竞品分析无论作为产品经理、运营岗位还是UE交互体验设计师,都是其必备技能和工作范畴之一。但是如何通过竞品分析提炼出有效信息,为业务或是设计决策提供有力的数据支撑,仍然值得我们进行更多的思考。在本文中 我整理了竞品分析的全过程,希望能帮到你。一、明确概念竞品分析是指对:现有......
  • 信息系统项目管理(高项)考试大纲分析
    大纲以及分值想要高效的学习,首先要先分析考试大纲。下面是信息系统项目管理(高项)新大纲No科目分值考点分布1新一代信息技术4分商业智能,物联网,大数据,互联网+,区块链,云计算,人工智能2信息化与信息系统5分信息技术发展,两化融合,信息系统阶段,大型信息系统,系统规划BSP,信息系统规划工具,信息......
  • 软件设计师考试大纲分析
    大纲以及分值想要高效的学习,首先要先分析考试大纲。下面是系统架构师新大纲上午题软件设计师分值计算机组成原理6分操作系统基础6分数据库基础6分网络与信息安全基础5分软件工程30分知识产权2分计算机英语5分项目管理2分程序设计语言基础知识5分数据结构与算法10分下午题更新计划后......
  • 系统架构师考试大纲分析
    大纲以及分值想要高效的学习,首先要先分析考试大纲。下面是系统架构师新大纲上午题系统架构设计师分值计算机组成原理3分操作系统基础5分数据库基础4分网络与信息安全基础4分软件工程15分知识产权3分计算机英语5分项目管理4分运筹学2分企业信息化5分可靠性分析与设计3分嵌入式系统2......
  • 系统分析师考试大纲分析
    大纲以及分值想要高效的学习,首先要先分析考试大纲。下面是系统分析师新大纲上午题系统分析师分值计算机组成原理6分操作系统基础5分数据库基础6分网络与信息安全基础5分软件工程15分知识产权3分计算机英语5分项目管理2分运筹学3分企业信息化5分可靠性分析与设计3分嵌入式系统3分系......