AQS,AbstractQueuedSynchronizer,即队列同步器
AQS即是AbstractQueuedSynchronizer,一个用来构建锁和同步工具的框架,包括常用的ReentrantLock、CountDownLatch、Semaphore等
AQS功能可以分为两类:独占锁和共享锁
它是构建锁或者其他同步组件的基础框架(如ReentrantLock、ReentrantReadWriteLock、Semaphore等),JUC并发包的作者(Doug Lea)期望它能够成为实现大部分同步需求的基础。它是JUC并发包中的核心基础组件。
AQS解决了子类实现同步器时涉及到的大量细节问题,例如获取同步状态、FIFO同步队列。基于AQS来构建同步器可以带来很多好处。它不仅能够极大地减少实现工作,而且也不必处理在多个位置上发生的竞争问题。
在基于AQS构建的同步器中,只能在一个时刻发生阻塞,从而降低上下文切换的开销,提高了吞吐量。同时在设计AQS时充分考虑了可伸缩行,因此J.U.C中所有基于AQS构建的同步器均可以获得这个优势。
AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态。
AQS使用一个int类型的成员变量state来表示同步状态,当state = 1时表示已经获取了锁,当state = 0时表示释放了锁。
它提供了三个方法(getState()、setState(int newState)、compareAndSetState(int expect,int update))来对同步状态state进行操作,当然AQS可以确保对state的操作是安全的。
AQS通过内置的FIFO同步队列来完成资源获取线程的排队工作,如果当前线程获取同步状态失败(锁)时,AQS则会将当前线程以及等待状态等信息构造成一个节点(Node)并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,则会把节点中的线程唤醒,使其再次尝试获取同步状态。
Exclusive 独占资源-ReentrantLock
Exclusive(独占,只有一个线程能执行,如 ReentrantLock)
Share 共享资源-Semaphore/CountDownLatch
Share(共享,多个线程可同时执行,如 Semaphore/CountDownLatch)
ReentrantReadWriteLock 实现独占和共享两种方式
/**
* The synchronization state.
*/
private volatile int state;
/**
* @return current state value
*/
protected final int getState() {
return state;
}
/**
* @param newState the new state value
*/
protected final void setState(int newState) {
state = newState;
}
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
public static void main(String[] args){
ReentrantLock lock=new ReentrantLock();
try {
if (lock.tryLock()){
//业务逻辑处理
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args){
// 最大同时能接收500个请求
Semaphore semaphore=new Semaphore(500);
try {
if (semaphore.tryAcquire()){
//业务逻辑处理
}
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
/**
* @author yanyugang
* @description ${todo}
* @date 2019/9/6 20:49
*/
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("====begin====");
// 匿名内部类
// 当前线程需要等待的线程数
CountDownLatch countDownLatch = new CountDownLatch(2) {
@Override
public void await() throws InterruptedException {
super.await();
System.out.println(Thread.currentThread().getName() + " count down is ok");
}
};
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is done");
// 释放锁
countDownLatch.countDown();
}
}, "thread1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is done");
// 释放锁
countDownLatch.countDown();
}
}, "thread2");
thread1.start();
thread2.start();
// Causes the current thread to wait until the latch has counted down to zero
countDownLatch.await();
System.out.println("====end====");
}
}
参考文档: