AQS 与 CAS
程序员文章站
2022-03-08 19:00:28
...
一 . CAS
CAS(compare and swap),是解决多线程情况下锁性能损耗的机制。在java中,sun.misc.Unsafe 类提供了硬件级别的原子操作来实现CAS。
二. CAS典型应用
java.util.concurrent.atomic 包下的类大多是使用CAS操作来实现的:AtomicInteger
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private volatile int value;// 初始int大小
// 省略了部分代码...
// 带参数构造函数,可设置初始int大小
public AtomicInteger(int initialValue) {
value = initialValue;
}
// 不带参数构造函数,初始int大小为0
public AtomicInteger() {
}
// 获取当前值
public final int get() {
return value;
}
// 设置值为 newValue
public final void set(int newValue) {
value = newValue;
}
//返回旧值,并设置新值为 newValue
public final int getAndSet(int newValue) {
/**
* 这里使用for循环不断通过CAS操作来设置新值
* CAS实现和加锁实现的关系有点类似乐观锁和悲观锁的关系
* */
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
// 原子的设置新值为update, expect为期望的当前的值
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// 获取当前值current,并设置新值为current+1
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
// 此处省略部分代码,余下的代码大致实现原理都是类似的
}
在竞争不是非常激烈的情况下,该包下的原子操作性能比使用 synchronized 关键字的方式高效的多。
三. AQS
AQS 是Java.util.concurrent包的核心类。
整个包中很多类的结构都是如此,比如Semaphore,CountDownLatch都有一个内部类Sync,而所有的Sync都是继承自AbstractQueuedSynchronizer。 所以说想要读懂Java并发包的代码,首先得读懂这个类。
AQS的核心是通过一个共享变量来同步状态,变量的状态由子类去维护。AQS所做的工作主要有两部分:
(1)线程阻塞队列的维护
(2)线程的阻塞与唤醒
共享变量的修改都是通过Unsafe类提供的CAS操作完成的。AbstractQueuedSynchronizer类的主要方法是acquire和release,它们是典型的模板方法。
acquire方法用来获取锁,返回true说明线程获取成功继续执行,一旦返回false则线程加入到等待队列中,等待被唤醒,release方法用来释放锁。 下面这4个方法由子类去实现
//独占模式获取
protected boolean tryAcquire(int arg)
//独占模式释放
protected boolean tryRelease(int arg)
//共享模式获取
protected int tryAcquireShared(int arg)
//共享模式释放
protected boolean tryReleaseShared(int arg)
四. AQS的用法
下面的SimpleLock类实现了一个最简单非重入的互斥锁的功能。
class SimpleLock extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -7316320116933187634L;
public SimpleLock() {
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() {
acquire(1);
}
public boolean tryLock() {
return tryAcquire(1);
}
public void unlock() {
release(1);
}
public boolean isLocked() {
return isHeldExclusively();
}
}
public static void main(String[] args) throws InterruptedException {
final SimpleLock lock = new SimpleLock();
lock.lock();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println(Thread.currentThread().getId() + " acquired the lock!");
lock.unlock();
}
}).start();
// 简单的让线程按照for循环的顺序阻塞在lock上
Thread.sleep(100);
}
System.out.println("main thread unlock!");
lock.unlock();
}
五. AQS源码分析
http://zhanjindong.com/2015/03/10/java-concurrent-package-aqs-overview