AQS--组件

本文详细介绍了AQS(AbstractQueuedSynchronizer)的工作原理,包括内部状态变量state的管理,公平锁与非公平锁的区别,以及基于AQS的ReentrantLock、Semaphore和CountDownLatch等组件的使用。AQS通过FIFO等待队列来管理竞争资源的线程,实现线程间的同步与通信。此外,还提供了Semaphore的信号量控制并发访问,CountDownLatch的倒计时等待,以及CyclicBarrier的循环栅栏功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. AQS原理:

在AQS内部会保存一个状态变量state,通过CAS修改该变量的值,修改成功的线程表示获取到该锁,没有修改成功,或者发现状态state已经是加锁状态,则通过一个Waiter对象封装线程,添加到等待队列中,并挂起等待被唤醒。
AQS维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。
原理图如下:
在这里插入图片描述

二.AQS定义两种资源共享方式:

  • Exclusive(独占):只有一个线程能执行,如ReentrantLock。又可分为公平锁和非公平锁:

      公平锁:按照线程在队列中的排队顺序,先到者先拿到锁
      非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的
    
  • Share(共享):多个线程可同时执行,如Semaphore/CountDownLatch。Semaphore、CountDownLatch、 CyclicBarrier、ReadWriteLock .

三. 公平锁和非公平锁有哪些区别?

公平锁指的是线程获取锁的顺序是按照加锁顺序来的,而非公平锁指的是抢锁机制,先 lock() 的线程不一定先获得锁。

四. ReentrantLock

  • ReentrantLock是基于AQS实现的

五.AQS的原理图-枷锁过程:

在这里插入图片描述

  • 枷锁过程描述:开始state==0
  1. 线程1 和线程2 同时通过CAS枷锁,这时候只有一个线程能成功
  2. 假设线程1成功,线程2失败,这时state=1,有个变量枷锁线=线程1
  3. 线程2加入等待队列中,等待线程1释放锁,线程1唤醒线程2,重新执行枷锁

六.AQS 组件总结:

  • Semaphore(信号量)-允许多个线程同时访问: synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,Semaphore(信号量)可以指定多个线程同时访问某个资源。
  • CountDownLatch (倒计时器): CountDownLatch是一个同步工具类,用来协调多个线程之间的同步。这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。
  • CyclicBarrier(循环栅栏): CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和 CountDownLatch 类似。CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await()方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。

七.组件代码示例:

  • CountDownLatch(倒计时器):个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待 ,即CountDownLatch允许一个或多个线程等待其他线程完成操作
public class CountDownLatchExample1 {

    private final static int threadCount= 200;

    public static void main(String[] args) throws Exception{
        ExecutorService exec = Executors.newCachedThreadPool();

       final CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        for(int i=0; i<threadCount; i++){
            final int threadNum = i;
            exec.execute(() ->{
                try {
                    test(threadNum);
                } catch (Exception e) {
                    log.error("exception 为 {}",e);
                }finally {
                    countDownLatch.countDown();//每次都是减1
                }
            });
        }
        countDownLatch.await();//保证上面的200线程都是执行完的

        //第一个参数代表等待的时间,第二个参数:时间的单位,超过10毫秒就执行
        countDownLatch.await(10, TimeUnit.MICROSECONDS);
        log.info("finish");
    }

    public static void test(int threadNum) throws Exception{
        Thread.sleep(100);
        log.info("threadNum === {}",threadNum);
        Thread.sleep(100);
    }
}

  • Semaphore(信号量):控制某个资源被同时访问的个数(控制并发的数量),例如:使用的场景:只能提供有限访问的资源,例如:mysql仅提供同一时刻20个资源访问.
public class SemaphoreExample1 {
    private final static int threadCount= 20;

    public static void main(String[] args) throws Exception{
        ExecutorService exec = Executors.newCachedThreadPool();
        //同时最多允许3个线程访问
        final Semaphore semaphore = new Semaphore(3);
        for(int i=0; i<threadCount; i++){
            final int threadNum = i;
            exec.execute(() ->{
                try {
                    //获取 一个 许可
                    semaphore.acquire();
                    //获取多个许可
                    //semaphore.acquire(3);
                    semaphore.tryAcquire();//尝试获取许可
                    test(threadNum);//最多有三个线程同时执行test()方法
                    //释放许可
                    semaphore.release();
                    //释放多个许可
                    //semaphore.release(3);
                } catch (Exception e) {
                    log.error("exception 为 {}",e);
                }
            });
        }

        log.info("finish");
    }

    public static void test(int threadNum) throws Exception{

        log.info("threadNum === {}",threadNum);
        Thread.sleep(100);
    }
}
  • CyclicBarrier(循环栅栏):是每个线程相互等待,等到达到设定的计数器时候,所有的线程在执行
public class CyclicBarrierExample1 {
  
    //5个线程相互等待,到五个线程准备好时候在执行
    private static CyclicBarrier barrier = new CyclicBarrier(5);

    public static void main(String[] args) throws Exception{
        Map map;
        HashMap hashMap = new HashMap();
        hashMap.put("key", "value");

        ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap();
        concurrentHashMap.put("hashmap", "hashmap");
        concurrentHashMap.get("hashmap");
        //这个参数就是核心线程池的数量
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i=0;i<10;i++){
            int threadNum = i;
            Thread.sleep(1000);
            exec.execute(() ->{
                try {
                    race(threadNum);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.info("exception {}",e);
                }
            });
        }

    }

    public static void race(int num) throws Exception{
        Thread.sleep(1000);
        log.info(" {}is ready",num);
        barrier.await();//等待达到五个线程,在执行
        log.info("{} continue",num);


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值