AQS深度讲解

1、ReentrantLock

核心:自旋、队列(双向链表Node)、cas、LockSupport.park()

当多个线程同时竞争锁时,会进行自旋的方式争抢锁,会保证只有一个线程通过cas拿到锁,其他线程会加入到双向链表(Node)中,并且会LockSupport.park()进入阻塞状态(线程进入waiting状态),释放cpu资源,当争抢到锁的线程运行完成,调用unLock方法,会释放队列最新进入的线程。当然在实际代码逻辑中,为了保证并发问题,很多地方都使用了自旋和cas(加入队列等等)。

公平锁是指当所有的线程必须先进入队列依次排队加锁的过程。

非公平锁是指当一个持有锁的线程释放锁时,刚加入的线程和队列中的最先加入的线程进行一个锁的争抢的过程。

可重入锁是通过state来实现的,当对同一个代码块重复加锁,state会+1,代表加锁的次数。而s释放锁也需要等到state变为0才能算是真正的释放锁。

2、阻塞队列BlockQueue

ArrayBlockQueue:数字结构的有界队列,基于ReentrantLock。

LinkedBlockQueue:链表结构的理论有界队列,当不设置队列长度时,默认为Integer.MAX_VALUE(2的31次幂)。

PriorityBlockingQueue:优先级堆支持的无界优先级队列。

DelayQueue:优先级堆支持的、基于时间的调度队列。

3、信号量Semaphore

通过初试化设置state来控制同一时间只能有指定线程同时进行,每当一个线程获取到信号量,则permits减一,当小于0时,线程会进行入队等待;当有线程释放信号量时,会通知下一个节点。相当于限制同一个时间只能拿到一定数量的共享锁。

Semaphore semaphore = new Semaphore(5);

api中有多种方法可以灵活使用:

acquire(int permits);    //获取信号量,支持中断
acquireUninterruptibly(int permits);    //获取信号量,不支持中断
tryAcquire(int permits);    //尝试获取信号量,成功返回true,不成功返回false
tryAcquire(int permits, long timeout, TimeUnit unit);    //在指定时间内尝试获取信号量

经典案例:买票时只有3个窗口,有十张票,有100个人买,怎样不会超卖?

答案:可以开启三个线程,将在扣库存的时候将信号量设置为1(表示同一时间只有一个线程扣减库存),当库存为0时,表示票以卖完。

4、CountDownLatch

通过共享锁的思想来实现的,初始化会设置state的初始值,代表同一时间能执行的线程的数。

核心方法:

countDown();    //state会-1
await();    //当state<=0时,才会走下去,state>0时,会进行自旋+cas获取,直到state变为0

经典案例:如何保证三个线程执行完才能执行下一部分代码?

答案:可以通过设置countDownLatch为3,线程跳出前执行countDown()方法,后面执行await()方法,当线程没有执行完时会进行自旋等待,直到state为0,才会执行下去。

5、线程栅栏CyclicBarrier

初始化默认设置state初始值,当队列中达到指定的线程时,会同时开启线程。

await();    //当state状态达到0时,自旋的方式开始执行线程,接近同时开启多个线程,而不会由于线程的启动时开销导致开启时间差异

经典案例:需要多个线程同时启动(其实利用countDownLatch倒过来使用也是可以实现)

6、Exchanger

相当于多个线程间随机交换数据。找不出应用场景,没什么卵用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值