应聘要求的cas_面试刷题22:CAS和AQS是什么?

java并发包提供的同步工具和线程池,底层是基于什么原理来设计和实现的呢?这个非常重要。

我是李福春,我在准备面试,今天的题目是:

CAS和AQS是什么?

答:CAS是一系列的操作集合,获取当前值进行计算,如果当前值没有改变,表示线程没有被占用,直接更新成功,否则,进行重试或者返回成功或者失败。 他是java并发工具包中lock-free的基础吗,依赖底层的cpu提供的特定指令实现。底层依赖于Unsafe的本地对象来实现。

AQS: 全称是AbstractQueuedSynchronizier,抽象队列同步器;他是各种同步工具锁的基础,比如ReentrantLock, CyclicBairier都是基于AQS来实现的。

CAS

以AtomicInteger为例子来分析一下CAS的应用。

首先看内部结构:

然后分析一下他的一个利用CAS实现的原子操作。

public final int getAndAddInt(Object o, long offset, int delta) {

int v;

do {

v = getIntVolatile(o, offset);

} while (!weakCompareAndSetInt(o, offset, v, v + delta));

return v;

}

这是一个自旋操作,利用Unsafe比较内存的偏移量,基于cpu指令保证修改的原子可见性。

使用CAS也是有缺点的:

1,自旋次数是假定冲突情况很少的理想情况,但是情况不理想容易过度消耗CPU;

2, ABA问题,一般使用加版本号的 AtomicStampedRefence来搞定;

在实际的工作中如何使用CAS来保证同步操作呢?

可以基于AtomicFieldLongUpdater来实现。比如下面是一个基于CAS实现的同步更新数据库索引的例子,代码如下:

public static class AtomicBTreePartition{

private volatile long lock;

private static final AtomicLongFieldUpdater

lockFieldUpdater

=AtomicLongFieldUpdater

.newUpdater(AtomicBTreePartition.class,"lock");

public void acquireLock(){

long t = Thread.currentThread().getId();

while (!lockFieldUpdater.compareAndSet(this, 0, 1)){

//数据库操作

}

}

public void releaseLock(){

}

}

AQS

她的组成核心主要有3个部分。

下面以ReentrantLock的非公平锁为例,分析一下它的加锁和释放锁的实现。

加锁操作代码:

public void lock() {

sync.acquire(1);

}

继续跟进:

public final void acquire(int arg) {

if (!tryAcquire(arg) &&

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

非公平锁的获取锁操作:

final boolean nonfairTryAcquire(int acquires) {

final Thread current = Thread.currentThread();

int c = getState();// 获取当前AQS内部状态量

if (c == 0) {

// 0表示无人占有,则直接用CAS修改状态位,

if (compareAndSetState(0, acquires)) {

// 不检查排队情况,直接争抢

setExclusiveOwnerThread(current);

//并设置当前线程独占锁

return true;

}

} else if (current == getExclusiveOwnerThread()) {

//即使状态不是0,也可能当前线程是锁持有者,因为这是再入锁

int nextc = c + acquires;

if (nextc < 0) // overflow

throw new Error("Maximum lock count exceeded");

setState(nextc);

return true;

}

return false;

}

排队竞争:

final boolean acquireQueued(final Node node, int arg) {

boolean interrupted = false;

try {

for (;;) {// 循环

final Node p = node.predecessor();// 获取前一个节点

if (p == head && tryAcquire(arg)) {

// 如果前一个节点是头结点,表示当前节点合适去tryAcquire

setHead(node); // acquire成功,则设置新的头节点

p.next = null; // 将前面节点对当前节点的引用清空

return interrupted;

}

if (shouldParkAfterFailedAcquire(p, node))

// 检查是否失败后需要park

interrupted |= parkAndCheckInterrupt();

}

} catch (Throwable t) {

cancelAcquire(node);// 出现异常,取消

if (interrupted)

selfInterrupt();

throw t;

}

小结

本节介绍了CAS和AQS的概念,然后以AtomicInteger为例切入原子操作是怎么利用CAS来保证的。

最后,以ReentrantLock的加锁操作,跟进了是如何利用AQS来保证内部的不同操作的。

算是初步探究了同步的实现原理。

原创不易,转载请注明出处,让我们互通有无,共同进步,欢迎沟通交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值