JUC之AQS原理-多线程与高并发

论坛 期权论坛 脚本     
匿名技术用户   2021-1-5 23:16   996   0

目录

(1)ReentranLock与AQS的关系

(2)动态调试ReentranLock程序的加锁调用过程

(3)AQS的类结构

(4)AQS一些子类实现的应用介绍


AQS是AbstractQueuedSynchronizer的缩写,它提供一个框架,用于实现依赖于先进先出(FIFO)等待队列的阻塞锁和相关的同步器(信号灯,事件等)。 此类旨在为大多数依赖单个原子{@code int}值表示状态的同步器提供有用的基础。 子类必须定义更改此状态的受保护方法,并定义该状态对于获取或释放此对象而言意味着什么。 鉴于这些,此类中的其他方法将执行所有排队和阻塞机制。 子类可以维护其他状态字段,但仅跟踪使用方法{@link #getState},{@ link #setState}和{@link #compareAndSetState}进行原子更新的{@code int}值的同步性。

AQS有很多具体的实现子类,比如ReentranLock、CountDownLatch、CyclicBarrier、Semaphore等核心都依赖AQS类实现。

(1)ReentranLock与AQS的关系

拿ReentranLock来说,其主要代码逻辑是依靠其内部抽象类Sync具体实现。Sync是AbstractQueuedSynchronizer的子类。

abstract static class Sync extends AbstractQueuedSynchronizer

而Sync抽象类又有两个实现子类FairSync和NonfairSync。

ReentrantLock与Sync-NonfairSync-NonfairSync的关系

Sync-NonfairSync-NonfairSync与AQS的关系

(2)动态调试ReentranLock程序的加锁调用过程

之前我们用ReentranLock实现了一个固定容量的容器,实现生产者和消费者的模型。

https://blog.csdn.net/phs999/article/details/109107758

package interview.question2;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用Condition的好处在于可以把生产线程和消费线程区分开进行唤醒
 * @param <T>
 */
public class Container2<T> {
    final private LinkedList<T> lists = new LinkedList<>();
    final private int MAX = 10;
    ReentrantLock lock = new ReentrantLock();
    Condition consumer = lock.newCondition();
    Condition producer = lock.newCondition();

    public void put(T o) {
        try {
            lock.lock();
            while (lists.size() == MAX) {
                System.out.println("生产完毕,生产者 "+Thread.currentThread().getName()+" 阻塞中");
                producer.await();
            }

            lists.add(o);
            consumer.signalAll();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public T get() {
        T t=null;
        lock.lock();
        try {
            while (lists.size() == 0) {
                System.out.println("库存为0,消费者 "+Thread.currentThread().getName()+" 阻塞中");
                consumer.await();
            }

            t = lists.removeFirst();
            producer.signalAll();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
           lock.unlock();
        }
        return t;
    }

    public synchronized int getCount() {
        return lists.size();
    }


    public static void main(String[] args) throws InterruptedException {
        Container2 c = new Container2();

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 5; j++) {//每个消费者线程消耗5个对象
                    System.out.println(Thread.currentThread().getName()+" 消费了 "+c.get()+" 库存剩余:"+c.getCount());
                }
            }, "consumer" + i).start();
        }

        TimeUnit.SECONDS.sleep(5);

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 25; j++) {//每个生产者线程生产25个对象
                    c.put(Thread.currentThread().getName() + " " + j);
                    System.out.println(Thread.currentThread().getName()+" 生产了 "+Thread.currentThread().getName()+" "+j+" 库存剩余:"+c.getCount());
                }
            }, "producer" + i).start();
        }
    }

}

我们对lock()方法加断点,调用过程如下:

如果compareAndSetState()方法将state状态值成功修改返回true,则执行setExclusiveOwnerThread()方法设置独占进行,当前线程获得独占锁。

如果compareAndSetState()方法没有将state状态值成功修改,返回false,则说明目前有线程已获得这个锁。

尝试获取锁,如果getState()返回的值是0,则可以继续使用CAS的方式修改state的值,如果不是0的话,则判断当前的获得锁的独占 线程是不是现在尝试获取的的这个线程,如果是,则是锁重入,只需要给state+1就行了。如果以上都不是,则尝试获取锁的线程进入等待队列。

未获得锁的线程加入等待线程队列。

使用CAS的方式将该线程已Node对象的方式加入到等待队列尾部。

(3)AQS的类结构

AQS类中state变量,对于ReentranLock来说,用于标识是否有线程获得锁,没有线程获得锁则该值为0.

对于CountDownLatch来说,则代表countdown()方法调用的次数,调用多少次后state为0时则线程唤醒。

该变量使用volatile修饰,保证线程可见性。同时该类中还有一个Node对象组成的双向列表。

AQS的核心就是cas+volatile的应用,volatile保证了state变量的线程可见性,cas用于线程修改state值以及将等待线程添加到等待队列(双向链表中)。

(4)AQS一些子类实现的应用介绍

ReentranLockCountDownLatch、CyclicBarrierSemaphore

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP