`
uule
  • 浏览: 6358061 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

FairSync与NonfairSync

 
阅读更多

state 为0,表示锁未被获取

不为0,表示已被获取

 

compareAndSetState(0, acquires)

        获取锁时,设置state为acquires

 

setExclusiveOwnerThread(current)

        获取锁时,设置线程为当前线程

 

可重入:

        已获取到锁时,再次进入时state 加上acquires即可

 

public class ReentrantLock implements Lock, java.io.Serializable {
     private final Sync sync;

     public ReentrantLock(boolean fair) {
         sync = fair ? new FairSync() : new NonfairSync();
     }

     public void lock() {
         sync.lock();
     }

     public void unlock() {
         sync.release(1);     // 这个1表示退出锁1次。
     }

     // 带超时限制的获取
  public boolean tryLock(long timeout, TimeUnit unit)
          throws InterruptedException {
      return sync.tryAcquireNanos(1, unit.toNanos(timeout));
  }

     // 其他代码省略
}

 可以看到,ReentrantLock都是把具体实现委托给内部类而不是直接继承自AbstractQueuedSynchronizer,这样的好处是用户不会看到不需要的方法,也避免了用户错误地使用AbstractQueuedSynchronizer的公开方法而导致错误

 

ReentrantLock的重入计数是使用AbstractQueuedSynchronizer的state属性的,state大于0表示锁被占用、等于0表示空闲,小于0则是重入次数太多导致溢出了。

 

 

ReentrantLock.Sync 

 

可重入锁内部实现的超类,主要实现了公平与非公平锁的共有方法,并提供了加锁操作的统一抽象:abstract void lock();,还有核心的释放锁的操作。

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;

    // 执行Lock.lock()方法,留给子类根据其公平性实现。
    // 子类化的最主要原因是允许非公平的快速路径。
    abstract void lock();

    // 非公平获取
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
      // 锁是空闲的,进行加锁必须用CAS来确保即使有多个线程竞争锁也是安全的
            if (compareAndSetState(0, acquires)) {
                // 加锁成功

                // 把当前线程设为锁的持有者,在获取前可用于判断是否是重入。
                setExclusiveOwnerThread(current);
                return true ;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
             // 锁被占用且当前线程是锁的持有者,说明是重入。
            int nextc = c + acquires;
            if (nextc < 0)
                   // 溢出。加锁次数从0开始,加锁与释放操作是对称的,
                   // 所以绝不会是小于0值,小于0只能是溢出。
                throw new Error("Maximum lock count exceeded");

            // 锁被持有的情况下,只有持有者才能更新锁保护的资源,
            // 所以这里不需要用CAS。
            setState(nextc);
            return true ;
        }
        return false ;
    }

    protected final boolean tryRelease(int releases) {
      // 先读取state是为了获得一个读屏障,owner不是volatile的。
        int c = getState() - releases;

        // 只有锁的持有者才能释放锁
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {// 锁重入计数减到0,需要真正释放锁了。
            free = true;
            setExclusiveOwnerThread( null);
        }
    // 如果c为0,写操作完成后,其他线程就会看到锁被释放了,
       // 所以setExclusiveOwnerThread必须在这个写之前完成。
        setState(c);
        return free;
    }

    protected final boolean isHeldExclusively() {
        // While we must in general read state before owner,
        // we don't need to do so to check if current thread is owner
        return getExclusiveOwnerThread() == Thread.currentThread();
    }

    final ConditionObject newCondition() {
        return new ConditionObject();
    }

    // Methods relayed from outer class
    final Thread getOwner() {
        return getState() == 0 ? null : getExclusiveOwnerThread();
    }

    final int getHoldCount() {
        return isHeldExclusively() ? getState() : 0; // 以state属性作为加锁次数。
    }

    final boolean isLocked() {
        return getState() != 0;     // 加锁次数为0表示没有被拥有
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
    }
}

 

ReentrantLock.FairSync

 

提供公平性的锁实现。实现公平性的关键在于:如果锁被占用且当前线程不是持有者也不是等待队列的第一个,则进入等待队列。

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1); //acquire会首先调用tryAcquire,所以公平策略的控制留给tryAcquire。
    }

    // tryAcquire的公平版本。除非是递归调用或没有等待者或者是第一个,否则不授予访问。
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState(); // 读关卡
        if (c == 0) {
             // 锁空闲
            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 ;
    }
}

 

ReentrantLock.NonfairSync

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    // 执行lock。尝试立即闯入,失败就退回常规流程
    final void lock() {
        if (compareAndSetState(0, 1))// 首先进行获取
             // 获取成功,把当前线程设为持有者
            setExclusiveOwnerThread(Thread.currentThread());
        else
             // 获取失败,进入常规流程:acquire会首先调用tryAcquire,
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

 

 

获取锁:

//NonfairSync 
final void lock() {  
	if (compareAndSetState(0, 1))  
		setExclusiveOwnerThread(Thread.currentThread());  
	else  
		acquire(1);  
}  
  
  
//FairSync  
final void lock() {  
	acquire(1);  
} 

 

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

 

1)在资源没有被占用的情况下:

非公平锁是:

                先state+1,然后直接得到锁,

而公平锁则是:

                先尝试去获取锁,如果得到了锁则state+1.

 

2)如果是同一线程,再次申请锁.

两种锁,表现基本一致,可以参考下面的代码块. 

else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    ReentrantLock源码的使用问题详解.docx

    ReentrantLock的实现主要依赖于3个内部类:Sync、FairSync和NonfairSync。它们都继承自AbstractQueuedSynchronizer(AQS),AQS是Java并发包中一个重要的抽象类,用于构建锁和其他同步组件的基础框架。 Sync是...

    Java并发之ReentrantLock类源码解析

    ReentrantLock类内部定义了两个实现类:NonfairSync和FairSync。NonfairSync是非公平锁,FairSync是公平锁。 ReentrantLock的构造方法 ReentrantLock类有两个构造方法: 1. ReentrantLock() 2. ReentrantLock...

    JUC核心类AQS的底层原理

    1. **`ReentrantLock`的`tryAcquire`实现**:在`ReentrantLock`中,`tryAcquire`方法的具体实现在`NonFairSync`和`FairSync`中有所不同。对于`NonFairSync`,它会尝试直接使用CAS操作来修改`state`值,如果成功,则...

    Java并发系列之Semaphore源码分析

    acquireSharedInterruptibly方法首先就是去调用tryAcquireShared方法去尝试获取,tryAcquireShared在AQS里面是抽象方法,FairSync和NonfairSync这两个派生类实现了该方法的逻辑。FairSync实现的是公平获取的逻辑,而...

    Java 多线程与并发(11-26)-JUC锁- ReentrantLock详解.pdf

    ReentrantLock的内部类Sync继承自AQS,进一步分为FairSync(公平锁)和NonfairSync(非公平锁)两个子类。公平锁确保线程按照它们请求锁的顺序获取锁,而非公平锁则不保证这种顺序,可能会有线程插队获取锁。 **...

    ReentrantLock代码剖析之ReentrantLock_lock

    `Sync`是一个抽象类,它是`ReentrantLock`的核心实现,分为公平锁`FairSync`和非公平锁`NonFairSync`两个子类。默认情况下,`ReentrantLock`使用的是非公平锁,因为非公平锁在大多数情况下具有更高的吞吐量。 `Sync...

    第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()1

    在构造函数中,`sync = new NonfairSync()` 或 `sync = new FairSync()` 分别用于创建非公平锁和公平锁,这里的`sync`是一个内部类,它是`AbstractQueuedSynchronizer`(AQS)的子类。 3. **内部类结构** - `Sync...

    AQS源码阅读笔记,画了两三天的AQS...

    3. `FairSync` 和 `NonFairSync`:`FairSync` 是一种公平锁,它继承自 `Sync`,并重写了 `tryAcquire(arg)` 方法以实现公平锁逻辑。`NonFairSync` 是一种非公平锁,它也继承自 `Sync`,但不保证公平性。 4. `Sync`...

    基于JDK源码解析Java领域中的并发锁,我们需要特别关注哪些内容?

    - **实现**:ReentrantLock通过AQS封装了静态内部类Sync,进一步细分为公平锁FairSync和非公平锁NonfairSync。在尝试获取锁时,公平锁遵循FIFO原则,而非公平锁则可能跳过等待队列中的线程。 3. **...

    Semaphore 源码解析

    Semaphore类有两个内部静态类——NonfairSync和FairSync,分别对应非公平锁和公平锁。在构造Semaphore时,可以通过传入布尔值决定使用哪种类型的锁。 在Semaphore中,`acquire()`方法用于获取一个许可,如果当前...

    Lock详解.pdf

    在ReentrantLock内部,公平锁(FairSync)和非公平锁(NonfairSync)都是对Sync的子类实现,分别实现了公平和非公平的锁获取策略。FairSync在尝试获取锁时会检查当前是否有其他线程在等待,而NonfairSync则不会,这...

    ReentrantLock源码分析

    ReentrantLock的内部实现分为两个子类:`FairSync`(公平锁)和`NonfairSync`(非公平锁)。这两个子类均继承自`Sync`抽象类。 - **FairSync**:按照请求顺序来分配锁,确保了锁获取的公平性,但可能会影响性能。 -...

    Java并发编程:深入解析抽象队列同步器(AQS)及其在Lock中的应用

    公平锁(FairSync)和非公平锁(NonfairSync)的实现是通过AQS的扩展来实现的。文章进一步阐释了AQS的多项特性,包括阻塞等待队列、共享/独占模式、公平/非公平锁定、可重入性,以及允许中断的能力。AQS作为基础框架...

    一文带你看懂Java中的Lock锁底层AQS到底是如何实现的.doc

    以ReentrantLock为例,它有两个内部类,`FairSync`(公平锁)和`NonfairSync`(非公平锁),它们都继承自AQS。`NonfairSync`的`lock()`方法会首先尝试通过CAS直接获取锁,失败后会调用AQS的`acquire()`方法。`...

    java并发之ReetranLock

    new FairSync() : new NonfairSync();} 公平锁的处理逻辑 公平锁的处理逻辑与非公平锁基本上是一致的,唯一的不同在于增加了 hasQueuedPredecessors 的逻辑判断,方法名就可知道该方法用来判断当前节点在同步队列...

    ReentrantLock源码详解--公平锁、非公平锁

    ReentrantLock的主要结构包括三个内部类:Sync、NonfairSync、FairSync。Sync是一个抽象类,实现了AQS的部分方法;NonfairSync实现了Sync,主要用于非公平锁的获取;FairSync实现了Sync,主要用于公平锁的获取。 ...

    21 更高级的锁—深入解析Lock.pdf

    sync对象是一个抽象类,有两个具体实现:FairSync(公平锁)和NonfairSync(非公平锁)。它们都继承自AbstractQueuedSynchronizer(AQS),AQS维护了一个volatile状态字段state,用于表示锁的状态,以及一个FIFO等待...

    java 线程公平锁与非公平锁详解及实例代码

    在ReentrantLock的内部,公平锁由FairSync类表示,非公平锁由NonfairSync类表示。在NonfairSync中,lock()方法直接尝试通过compareAndSetState(0, 1)原子地设置锁的状态,如果成功,线程就获得了锁;如果失败,它会...

    Java 多线程与并发(12-26)-JUC锁- ReentrantReadWriteLock详解.pdf

    NonfairSync和FairSync分别代表非公平和公平的锁策略,继承自Sync。 - ReadLock和WriteLock是内部类,实现了Lock接口,分别对应读锁和写锁的接口。 通过理解ReentrantReadWriteLock的工作原理和设计,开发者可以更...

    【并发编程】简单化理解AQS和ReentrantLock.pdf

    - `NonfairSync`实现了非公平锁逻辑。 #### 7. 理解加锁过程 - **加锁流程**: - 尝试获取锁状态,如果状态为0则尝试CAS设置为1。 - 如果获取失败,将当前线程加入队列,并自旋等待前驱节点释放锁。 - 成功...

Global site tag (gtag.js) - Google Analytics