目录
原理
概述
-
如果被请求的
共享资源
空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态 -
如果被请求的
共享资源
被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制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);
过程
- 设定令牌总数量,子线程只有获取到
指定数量
的令牌,才被允许执行操作