发编程系列(十三)并发编程常用API(1)之ReentrantLock与Semaphore

目录

1.ReentrantLock

1. ReentrantLock 实现Lock接口(实际就是锁)

1.2 内部类Sync类的源码解析

1.3 内部类FairSync(公平锁)源码解析

1.4 内部类NonFairSync(非公平锁)源码解析

2 ReentrantLock公平锁加锁及解锁过程

2.1:进入FairSync的Lock方法

2.2:调用父类AQS的acquire方法

3. 解锁过程:

3.1:ReentrantLock解锁方法如下:

3.2:调用父类AQS的release()方法

3.3:tryrelease()方法需要子类实现

3.21  ReentrantLock非公平锁加锁及解锁过程

4. ReentrantLock的公平锁VS非公平锁

2.Semaphore

1.1 Semaphore内部类Sync源码解析

1.2 NonfairSync源码解析

1.3 FairSync 源码解析

2.1Semaphore类的非公平模式获取许可源码解析

3:acquire调用父类AQS中的AcquireSharedinterruptbly方法

4:AcquireSharedinterruptbly方法调用的tryAcquireShared方法在非公平模式下的实现如下

5:tryAcquireShared方法调用的NonfairTryAcquireShared方法如下:详细参考:1.1 Sync源码解析

6:tryAcquireShared方法返回小于0,则获取资源失败,执行doAcquireSharedInterruptibly方法

3.1 非公平模式释放许可资源源码解析

1:释放许可

2:release方法调用AQS中的releaseShared方法

3:其中tryReleaseShared需要子类实现

4:如果tryReleaseShared返回true将执行都releaseShared方法,

4. 公平模式获取许可源码分析



序号名称链接地址
1并发编程系列(一)创建线程的三种方式及线程如何完成上下文如何切换https://blog.csdn.net/qq_38130094/article/details/103443997
2并发编程系列(二)之线程的中断https://blog.csdn.net/qq_38130094/article/details/103444171
3 并发系列(三)线程常用的方法https://blog.csdn.net/qq_38130094/article/details/103446126
4并发编程系列(四)之Thread类源码分析(一)https://blog.csdn.net/qq_38130094/article/details/103448160
5并发编程系列(五)volatile关键字详解https://blog.csdn.net/qq_38130094/article/details/103448564
6并发编程系列(六)volatile 之 as-if-serial 指令重排 volatile内存语义 volatile原理https://blog.csdn.net/qq_38130094/article/details/103543998
7线程系列(七)synchronized使用方式https://blog.csdn.net/qq_38130094/article/details/103537663
8 线程系列(八)synchronized实现原理与应用https://blog.csdn.net/qq_38130094/article/details/103537668
9并发编程系列(九)ThreadLocala是如何解决共享变量的并发问题及源码分析https://blog.csdn.net/qq_38130094/article/details/103665098
10并发编程系列(十)AQS同步器独占锁加锁与解锁-源码解读https://blog.csdn.net/qq_38130094/article/details/103540315
11并发编程系列(十一)AQS同步器共享锁加锁解锁源码解读https://blog.csdn.net/qq_38130094/article/details/103646505
12并发编程系列(十二)AQS同步器条件锁(Condition)加锁解锁源码解读https://blog.csdn.net/qq_38130094/article/details/103679146
13发编程系列(十三)ReentrantLock 重入锁https://blog.csdn.net/qq_38130094/article/details/103843779
14发编程系列(十四)Semaphore信号量https://blog.csdn.net/qq_38130094/article/details/103846420
15发编程系列(十五) CountDownLatch闭锁https://blog.csdn.net/qq_38130094/article/details/103855632
16并发编程系列(十六) CyclicBarrierhttps://blog.csdn.net/qq_38130094/article/details/103859704

1.ReentrantLock

1. ReentrantLock 实现Lock接口(实际就是锁)

//Lock源码解读
public interface Lock {

    /**
     * 加锁
     */
    void lock();

    /**
     * 加锁并响应中断
     */
    void lockInterruptibly() throws InterruptedException;

    /**
     * 只有空闲的才能获取锁,返回boolean值
     */
    boolean tryLock();

    /**
     *在指定时间内获取锁,可以响应中断
     */
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    /**
     *解锁
     */
    void unlock();

    /**
     * 返回condition对象
     */
    Condition newCondition();
}

1.2 内部类Sync类的源码解析

ReentrantLock类的内部共存咋iSync,NonfairSync,FairSync三个类,NonfairSync与FairSync类继承自Sync,Sync继承自 AbstractQueuedSynchronizer

    //重入锁基础的同步控制器
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * 加锁方法,由Sync的子类FairSync和NonfairSync实现
         */
        abstract void lock();

        /**
         * 非公平方式加锁
         */
        final boolean nonfairTryAcquire(int acquires) {
            //当前线程
            final Thread current = Thread.currentThread();
            //当前线程的状态,即AQS中的state状态
            int c = getState();
            //c等于0表示没有线程持有state状态
            if (c == 0) {
                //CSA修改state状态,如果CAS成功,即加锁成功
                if (compareAndSetState(0, acquires)) {
                    //设置当前线程已独占的方式持有锁
                    setExclusiveOwnerThread(current);
                    //返回加锁成功
                    return true;
                }
            }
            //如果c不等于0,表示此时锁被占有
            //如果当前的线程就是锁的持有者
            else if (current == getExclusiveOwnerThread()) {
                //发生重入,增加重入的次数
                int nextc = c + acquires;
                如果nextc小于0,即发生了int类型的溢出
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                //设置state状态
                setState(nextc);
                //返回重入加锁成功
                return true;
            }
            //返回加锁失败
            return false;
        }
        //对类AQS中的tryRelease()重写
        protected final boolean tryRelease(int releases) {
            //获取state状态,减去要释放的资源releases
            int c = getState() - releases;
            //如果当前线程不是锁的拥有者
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            //是否完全释放锁
            boolean free = false;
            //如果c等于0
            if (c == 0) {
                //表示已经完全释放,没有任何线程持有锁
                free = true;
                //将锁拥有者置为null
                setExclusiveOwnerThread(null);
            }
            setState(c);
            //返回锁是否 被完全释放
            return free;
        }
        //对类AQS的isHeldExclusively重写
        protected final boolean isHeldExclusively() {
            // 校验当前线程是否与持有锁的线程相等
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
        //返回一个AQS内部类ConditionObject对象
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // 返回锁的持有者
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
        //返回重如锁的进入次数
        final int getHoldCount() {
            //如果isHeldExclusively为true
            //这说明当前线程是锁的持有者,返回state
            //否则返回0
            return isHeldExclusively() ? getState() : 0;
        }
        //是否已经被加锁
        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * 通过流反序列化对象
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

1.3 内部类FairSync(公平锁)源码解析

   /**
     * FairSync 继承Sync,实现公平锁
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        //加锁
        final void lock() {
            //调用父类方法实现加锁
            acquire(1);
        }

        /**
         * 实现父类tryAcquire方法 重写
         */
        protected final boolean tryAcquire(int acquires) {
            //当前线程
            final Thread current = Thread.currentThread();
            //锁的状态
            int c = getState();
            //c等于0,表示未被锁定
            if (c == 0) {
                //hasQueuedPredecessors是父类的方法
                //用于查询是否有等待锁的时间比当前线程更长的线程
                //如果没有优先级比当前线程等待更久的线程
                //则通过CAS设置state状态从0变成acquires
                //如果cas设置成功,说明线程加锁成功
                //设置锁的持有者为当前线程
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    //加锁成功
                    return true;
                }
            }
            //如果c不等于0
            //判断当前线程是不是锁的持有者
            //如果是,则发生重进入
            else if (current == getExclusiveOwnerThread()) {
                //nextc等于c加acquires
                int nextc = c + acquires;
                //c<0发生溢出
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                //返回加锁成功
                return true;
            }
            //返回加锁失败
            return false;
        }
    }

1.4 内部类NonFairSync(非公平锁)源码解析

    /**
     *非公平锁
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         *加锁
         */
        final void lock() {
            //cas使state从0变成1
            //如果cas成功,则将当前线程设置为锁的持有者
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                //如果cas失败,则调用父类AQS中的acquire方法进行加锁
                acquire(1);
        }
        //实际是调用子类的nonfairTryAcquire方法
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

2 ReentrantLock公平锁加锁及解锁过程

ReentrantLock的Lock方法调用Sync的lock方法,Sync有公平锁和非公平锁两种情况

加锁过程:

2.1:进入FairSync的Lock方法

final void lock(){
    acquire(1);
}

2.2:调用父类AQS的acquire方法

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

3:父类AQS的accquire方法调用tryAcquire方法,需要子类实现

    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

4:tryAcquire方法在公平锁中的实现,

请参考上方1.3 内部类FairSync(公平锁)源码解析tryAcquire()方法

3. 解锁过程:

3.1:ReentrantLock解锁方法如下:

    public void unlock() {
        sync.release(1);
    }

3.2:调用父类AQS的release()方法

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

3.3:tryrelease()方法需要子类实现

请参考1.2 内部类Sync类的源码解析的tryrelease()方法

3.21  ReentrantLock非公平锁加锁及解锁过程

3.22:非公平锁的加锁入口与公平锁加锁一样都是lock方法,只是调用的Sync对的引用不同

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

3.23:NonfairSync中对lock方法实现如下,细节请参考1.3 内部类NonFairSync(非公平锁)源码解析

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

3.24:与公平锁fairSync中的lock方法不同的是,NonfairSync中对lock方法直接进行CAS操作,如果CAS成功就设置锁的持有者为当前线程--非公平 的体现

final void lock(){
    acquire(1);
}

3.25:如果NonfairSync中对lock方法CAS失败,这说明有竞争者,将会进入父类CAS中的acquire方法

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

3.26:tryAcquire依旧需要子类实现,NonfairSync中对tryAcquire方法实现如下

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

3.27:NonfairSync中对tryAcquire调用的NonfairSync方法是父类中的方法,请参考1.2 内部类Sync类的源码解析中的NonfairSync方法

        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;
        }

3.28:与公平锁不同是,公平锁多加了hasQueuedPredecessors方法的调用

        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;
        }
    }

hasQueuedPredecessors方法是判断等待队列中是否存在当前线程先入队的线程,公平锁加锁需要先对等待队列的线程做出让步,先来后到,非公平锁不管先来后到,直接加锁;如果NonfairSync方法返回false,即非公平锁加锁失败,回到AQS中的accquire方法

4. ReentrantLock的公平锁VS非公平锁

两者之间没有具体的好坏之分,根据使用场景选择对应的锁技术

公平锁---侧重的是公平性

非公平锁--侧重的是并发性

非公平锁对锁的竞争是抢占式的(队列中的线程除外)线程在进入等待队列前进行两次尝试,这大大增大了获取锁的机会,这种好处提现在两个方面:

1:线程不比加入等待队列就可以获得锁,不仅免去了构造节点加入队列繁琐的操作,同时也省去了线程阻塞唤醒的开销,线程阻塞和唤醒涉及到线程上下文的切换和操作系统调用,是非常耗时的,在高并发情况下如果线程持有锁的时间非常短,短到线程入队阻塞的过程超过线程持有并释放的时间开销,那么这种抢占式特性对并发的提升更加明显

2:减少CAS竞争,如果线程必须要加入阻塞队列才能获取锁,那入队时CAS竞争将异常激烈CAS操作虽然不会导致失败线程挂起但是不断失败重试导致的对CPU的浪费也不能忽视

2.Semaphore

主要做并发控制;控制并发提升性能

Semaphore底层是基于AbstractQeuedSynchronizer来实现的所以Semaphore的数据结构也是依托于AQS的数据结构

1.1 Semaphore内部类Sync源码解析

    /**
     * 内部类Sync继承自AQS
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;
        //构造器
        Sync(int permits) {
            setState(permits);
        }
        //获得许可
        final int getPermits() {
            return getState();
        }
        //共享模式下非公平方式获取资源
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                //获取许可
                int available = getState();
                //剩余许可
                int remaining = available - acquires;
                //许可小于0或者CAS设置状态成功
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    //返回remaining
                    return remaining;
            }
        }
          //共享模式下释放资源
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                 //获取的许可数
                int current = getState();
                //增加许可
                int next = current + releases;
                //溢出的情况
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                //如果cas成功
                if (compareAndSetState(current, next))
                    //返回true
                    return true;
            }
        }
         //减少许可数
        final void reducePermits(int reductions) {
            for (;;) {
                //获取许可
                int current = getState();
                //剩余可用的许可
                int next = current - reductions;
                if (next > current) // underflow
                    throw new Error("Permit count underflow");
                //cas成功
                if (compareAndSetState(current, next))
                    return;
            }
        }
            //获取并返回所有许可
        final int drainPermits() {
            for (;;) {
                //获取许可数
                int current = getState();
                //如果current等于0或者cas成功
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }
    }

Sync类的属性相对简单,只有一个版本号

方法名左用
getPermits
获取许可
nonfairTryAcquireShared
共享模式下非公平策略获取
tryReleaseShared
共享模式下进行释放
reducePermits
根据指定的缩减减少可用许可的数目
drainPermits
获取并返回可用的所有许可

1.2 NonfairSync源码解析

NonfairSync类继承自Sync类,表示采用非公平策略获取资源,其中有一个tryAcquireShared方法,重写AQS的tryAcquireShared方法:

    /**
     * 非公平版本
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }
        //共享模式下获取资源
        protected int tryAcquireShared(int acquires) {
            //调用父类Sync中的NonfairSyncTryAcquireShared方法
            return nonfairTryAcquireShared(acquires);
        }
    }

1.3 FairSync 源码解析

1:FairSync 类继承了Sync类,表示采用公平策略获取资源,其中只有一个tryAcquireShared方法,重写了AQS的tryAcquireShared:

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

        FairSync(int permits) {
            super(permits);
        }
        //共享模式下获取资源
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                //同步队列存在比当前线程等待更久的结点
                //如果存在则返回-1
                if (hasQueuedPredecessors())
                    return -1;
                //获取state状态
                int available = getState();
                //剩余时间
                int remaining = available - acquires;
                //如果剩余许可小于0或者cas成功
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }

2.1Semaphore类的非公平模式获取许可源码解析

    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

3:acquire调用父类AQS中的AcquireSharedinterruptbly方法

   public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        //如果线程被中断
        if (Thread.interrupted())
            throw new InterruptedException();
        //tryAcquireShared方法需要子类实现
        //如果tryAcquireShared方法返回小于0
        //则获取资源失败
        if (tryAcquireShared(arg) < 0)
            //调用doAcquireSharedInterruptibly方法
            doAcquireSharedInterruptibly(arg);
    }

4:AcquireSharedinterruptbly方法调用的tryAcquireShared方法在非公平模式下的实现如下

    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }

5:tryAcquireShared方法调用的NonfairTryAcquireShared方法如下:详细参考:1.1 Sync源码解析

     final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

6:tryAcquireShared方法返回小于0,则获取资源失败,执行doAcquireSharedInterruptibly方法

    private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

3.1 非公平模式释放许可资源源码解析

1:释放许可

  public void release() {
        sync.releaseShared(1);
    }
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

2:release方法调用AQS中的releaseShared方法

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

3:其中tryReleaseShared需要子类实现

        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

4:如果tryReleaseShared返回true将执行都releaseShared方法,

   private void doReleaseShared() {

        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

4. 公平模式获取许可源码分析

公平模式获取许可的acquire方法与非公平模式下获取许可是一样的,不同的是tryAcquireShared方法的实现;与非公平模式相比,公平模式多了hasQueuedPredecessors

        protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }
    public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

公平模式释放许可和非公平模式是一样的

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值