`
spring5365
  • 浏览: 71461 次
  • 性别: Icon_minigender_1
  • 来自: 钓鱼岛
社区版块
存档分类
最新评论

ReentrantReadWriteLock

 
阅读更多

最近研究了一下java中的锁,在看读写锁的代码时,发现很难理解javadoc中关于这个类的解释。于是自己对着代码理解了一下,在此记录,有些地方看得不是太明白,如有错误请纠正。

 

从不同的视角看锁,锁具有如下特性:

公平性:

公平锁和非公平锁:如果获取锁的顺序是按照请求锁的顺序进行的,那么就是公平锁,否则就是非公平锁

 

互斥性:

独占锁和共享锁:独占锁只能由一个线程持有,如果独占锁是可重入锁(同一线程可以获取多次),则同一线

                            程可以获取多次。

                            共享锁可由多个线程获取。

 

ReentrantReadWriteLock可以提高锁的并发性,读读共享,读写、写写互斥。非公平锁会优先为等待时间最

长的那个写线程分配写入锁(由非公平读锁的实现决定)。

 

读写锁的公平性:

    非公平读锁:非公平读获取读锁时,判断队列头结点是不是独占结点,是则自旋等待。

    非公平写锁:非公平写获取锁时,先尝试直接获取写锁。

    公平读锁:不是等待队列的头结点时,不能获取读锁。

    公平写锁:不是等待队列的头结点时,不能获取写锁。

 

锁降级:

    锁降级获取锁的顺序:

    writelock.lock();

    readlock.lock();

    writelock.unlock();

    readlock.unlock();

    锁降级获取写锁时,不能有线程再获取读锁,当修改完数据时,当前线程获取读锁后,可继续执行操作。

    不会被其它写线程影响,因为此时其它写线程获取不到锁。

 

锁升级:

   锁升级是不允许的,这里看源代码的时候比较困惑,代码里实际上是可以获取取锁的。不过,这里存在

   一个死锁条件,锁升级获取锁的顺序如下:

    readlock.lock();

    writelock.lock();

    readlock.unlock();

    writelock.unlock();

 

    为什么会死锁?

    因为要想获取写锁,要释放所有读锁,当多个线程同时获取到读锁再获取写锁时,会在获取写锁处等待读

    锁释放,导致死锁。

 

 

        //读写锁用高16位表示共享锁,低16位表示独占锁
        static final int SHARED_SHIFT   = 16;
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        //可表示锁的最大值
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        //计算共享锁数量
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        //计算独占锁数量
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

        /**
         获取独占锁
         **/
        protected final boolean tryAcquire(int acquires) {
            Thread current = Thread.currentThread();
            int c = getState();
            int w = exclusiveCount(c);
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
            }
            if ((w == 0 && writerShouldBlock(current)) ||
                !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }

        1.如c不等于0,w等于0,此时线程持有共享锁,不能获取独占锁
        2.如c不等于0,获取锁的数量大于最大锁数量,抛异常
        3.如果w等于0(其它线程未持有独占锁),这时看写是不是应该被阻塞
        4.如果更新锁状态成功,返回true
        5.如果c等于0,返回true

        
        /**
         获取共享锁
         **/
        protected final int tryAcquireShared(int unused) {
            Thread current = Thread.currentThread();
            int c = getState();
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            if (sharedCount(c) == MAX_COUNT)
                throw new Error("Maximum lock count exceeded");
            if (!readerShouldBlock(current) &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != current.getId())
                    cachedHoldCounter = rh = readHolds.get();
                rh.count++;
                return 1;
            }
            return fullTryAcquireShared(current);
        }
        
        1.如果写锁由其它线程持有,获取失败
        2.如果共享锁是最大值,获取失败
        3.判断读锁是否该阻塞,公平锁判断该线程是否为头结点,是头结点获取成功,不是则阻塞
          非公平锁判断头结点的下一等待结点是否在共享模式下等待,是则成功,不是则阻塞
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics