AQS

原理

概述

在这里插入图片描述

  • 如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态

  • 如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中

  • AQS使用一个int成员变量来表示同步状态,通过内置的FIFO队列来完成获取资源线程的排队工作。AQS使用CAS对该同步状态进行原子操作实现对其值的修改

    //共享变量,使用volatile修饰保证线程可见性
    private volatile int state;

CLH队列

在这里插入图片描述

  • CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系),AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配

对资源的共享方式

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

    公平与非公平:调用addWaiter()方法的时候,是否先尝试获取锁,如果能获取到,就运行该线程,不能则添加到同步队列的尾部

  • Share(共享): 多个线程可同时执行,如Semaphore、CountDownLatch、 CyclicBarrier、ReadWriteLock

Condition原理

在这里插入图片描述

组件介绍

Lock

Lock用法
//加锁
void lock();
//解锁
void unlock();
//可中断获取锁,与lock()不同之处在于可响应中断操作,即在获
//取锁的过程中可中断,注意synchronized在获取锁时是不可中断的
void lockInterruptibly() throws InterruptedException;
//尝试非阻塞获取锁,调用该方法后立即返回结果,如果能够获取则返回true,否则返回false
boolean tryLock();
//根据传入的时间段获取锁,在指定时间内没有获取锁则返回false,如果在指定时间内当前线程未被中并断获取到锁则返回true
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//获取等待通知组件,该组件与当前锁绑定,当前线程只有获得了锁
//才能调用该组件的wait()方法,而调用后,当前线程将释放锁。
Condition newCondition();
ReentrantLock独有用法
//查询当前线程保持此锁的次数。
int getHoldCount() 
//返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。      
protected  Thread   getOwner(); 
//返回一个 collection,它包含可能正等待获取此锁的线程,其内部维持一个队列,这点稍后会分析。      
protected  Collection<Thread>   getQueuedThreads(); 
//返回正等待获取此锁的线程估计数。   
int getQueueLength();
// 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
protected  Collection<Thread>   getWaitingThreads(Condition condition); 
//返回等待与此锁相关的给定条件的线程估计数。       
int getWaitQueueLength(Condition condition);
// 查询给定线程是否正在等待获取此锁。     
boolean hasQueuedThread(Thread thread); 
//查询是否有些线程正在等待获取此锁。     
boolean hasQueuedThreads();
//查询是否有些线程正在等待与此锁有关的给定条件。     
boolean hasWaiters(Condition condition); 
//如果此锁的公平设置为 true,则返回 true。     
boolean isFair() 
//查询当前线程是否保持此锁。      
boolean isHeldByCurrentThread() 
//查询此锁是否由任意线程保持。        
boolean isLocked()    
Condition用法
/**
  * 使当前线程进入等待状态直到被通知(signal)或中断
  * 当其他线程调用singal()或singalAll()方法时,该线程将被唤醒
  * 当其他线程调用interrupt()方法中断当前线程
  * await()相当于synchronized等待唤醒机制中的wait()方法
  */
 void await() throws InterruptedException;
 //当前线程进入等待状态,直到被唤醒,该方法不响应中断要求
 void awaitUninterruptibly();
 //调用该方法,当前线程进入等待状态,直到被唤醒或被中断或超时
 //其中nanosTimeout指的等待超时时间,单位纳秒
 long awaitNanos(long nanosTimeout) throws InterruptedException;
  //同awaitNanos,但可以指明时间单位
  boolean await(long time, TimeUnit unit) throws InterruptedException;
 //调用该方法当前线程进入等待状态,直到被唤醒、中断或到达某个时
 //间期限(deadline),如果没到指定时间就被唤醒,返回true,其他情况返回false
  boolean awaitUntil(Date deadline) throws InterruptedException;
 //唤醒一个等待在Condition上的线程,该线程从等待方法返回前必须
 //获取与Condition相关联的锁,功能与notify()相同
  void signal();
 //唤醒所有等待在Condition上的线程,该线程从等待方法返回前必须
 //获取与Condition相关联的锁,功能与notifyAll()相同
  void signalAll();

CountDownLatch(倒计时器)

用法
// 创建,并指定总并发量
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
// 线程执行完毕,计数器减一
countDownLatch.countDown();
 // 若计数器不为0,则不往下执行
countDownLatch.await();
// 若计数器不为0,且没过超时时间,则不往下执行
countDownLatch.await(10, TimeUnit.MILLISECONDS);
过程
  • 子线程执行到countDown()之后暂停,待计数器为0时再往下执行
  • 主线程执行到await()之后阻塞,待计数器为0时再往下执行
  • 不可重入,计数为0不可恢复

CyclicBarrier(循环栅栏)

用法
// 创建,并指定需要等待同步执行的线程数
private static CyclicBarrier barrier = new CyclicBarrier(5);
// 创建,并指定需要等待同步执行的线程数,设置到达同步点后的操作
private static CyclicBarrier barrier = new CyclicBarrier(5, () -> {
log.info("callback is running");
});
// 设置同步屏障
barrier.await();
// 设置同步屏障,并指定每个同步的超时时间
barrier.await(2000, TimeUnit.MILLISECONDS);
// 手动重置
barrier.reset();
过程
  • 子线程执行到await()之后暂停,待计数器为0时再往下执行
  • 不会阻塞主线程
  • 可重入,计数为0后会恢复

Semaphore(信号量)

用法
// 创建,并指定最大许可数
final Semaphore semaphore = new Semaphore(3);
// 获取一个许可
semaphore.acquire();
// 获取多个许可
semaphore.acquire(x);
// 尝试获取一个许可
if (semaphore.tryAcquire())
// 设定的时间内,尝试获取一个许可
if (semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS))
// 释放一个许可
semaphore.release();
// 释放多个许可
semaphore.release(x);
过程
  • 设定令牌总数量,子线程只有获取到指定数量的令牌,才被允许执行操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发财猪猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值