zoukankan      html  css  js  c++  java
  • 深入分析ReentrantLock公平锁和非公平锁的区别 (转)

      

      在ReentrantLock中包含了公平锁和非公平锁两种锁,通过查看源码可以看到这两种锁都是继承自Sync,而Sync又继承自AbstractQueuedSynchronizer,而AbstractQueuedSynchronizer又继承自AbstractOwnableSynchronizer,下面是类的继承关系图: 
    lock继承关系图

    其中AbstractOwnableSynchronizer是提供了设置占用当前锁的线程信息的方法,主要的锁的实现还是在AbstractQueuedSynchronizer中实现的,在AbstractQueuedSynchronizer中通过CLH队列实现了多线程锁的排队使用,但是该队列的实现并不能保证锁的公平竞争,但是在某些业务场景中会需要保证先到的线程先得到锁,所以就有了公平锁和非公平锁的诞生。

    通过分析ReentrantLock中的公平锁和非公平锁的实现,其中tryAcquire是公平锁和非公平锁实现的区别,下面的两种类型的锁的tryAcquire的实现,从中我们可以看出在公平锁中,每一次的tryAcquire都会检查CLH队列中是否仍有前驱的元素,如果仍然有那么继续等待,通过这种方式来保证先来先服务的原则;而非公平锁,首先是检查并设置锁的状态,这种方式会出现即使队列中有等待的线程,但是新的线程仍然会与排队线程中的对头线程竞争(但是排队的线程是先来先服务的),所以新的线程可能会抢占已经在排队的线程的锁,这样就无法保证先来先服务,但是已经等待的线程们是仍然保证先来先服务的,所以总结一下公平锁和非公平锁的区别:

    1、公平锁能保证:老的线程排队使用锁,新线程仍然排队使用锁。 
    2、非公平锁保证:老的线程排队使用锁;但是无法保证新线程抢占已经在排队的线程的锁。

    公平锁的tryAcquire

     /**
             * Fair version of tryAcquire.  Don't grant access unless
             * recursive call or no waiters or is first.
             */
            protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    // !hasQueuedPredecessors()保证了不论是新的线程还是已经排队的线程都顺序使用锁
                    if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0)
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }

    非公平锁的

    /**
             * Performs non-fair tryLock.  tryAcquire is implemented in
             * subclasses, but both need nonfair try for trylock method.
             */
            final boolean nonfairTryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    // 新的线程可能抢占已经排队的线程的锁的使用权
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }

    ReentrantLock和LockSupport

  • 相关阅读:
    sql中实现先排序后分组
    mysql中的锁机制之概念篇
    PHP对程序员的要求更高
    给初学PHP的学习线路和建议
    设计模式六大原则
    Mysql忘记密码怎么办
    数据库 sql
    精准优化 if…else ,干掉,过多,烂代码!
    JDK1.8 新特性(全)
    mysql 如何修改 删除 添加 表主键
  • 原文地址:https://www.cnblogs.com/snowwhite/p/9478754.html
Copyright © 2011-2022 走看看