java模拟器同步器,并发编程-AQS同步器

AQS(AbstractQueuedSynchronizer同步器):它提供了一个FIFO队列,是用来构建锁或者其他同步组件的基础框架。

AQS是一个抽象类,主要是通过继承的方式来使用,它本身没有实现任何的同步接口,仅仅是定义了同步状态的获取以及释放的方法来提供自定义的同步组件。

常用框架

ReentrantLock、Fork/Join、CountDownLatch(计数器)、Semaphore(限流信号量)等

底层实现原理

结合CAS compareAndSwapInt实现。

b0f73845d2a2

执行流程图

Condition 单向链表,调用await释放锁,当前线程阻塞。

b0f73845d2a2

核心参数

a.Node结点 采用双向链表的形式存放正在等待的线程 waitStatus状态、thread等到锁的线程

CANCELLED,值为1,表示当前的线程被取消;

SIGNAL,值为-1,释放资源后需唤醒后继节点;

CONDITION,值为-2, 等待condition唤醒;

PROPAGATE,值为-3,工作于共享锁状态,需要向后传播,比如根据资源是否剩余,唤醒后继节点;

值为0,表示当前节点在sync队列中,等待着获取锁。

b.Head 头结点 等待队列的头结点

c.Tail 尾结点 正在等待的线程

d.State 锁的状态 0无锁、1已经有线程获取锁,默认为0

当前线程重入时State不断+1 ,当调用unlock方法时State-1,完全释放锁的情况下归零,且设置exclusiveOwnerThread=null

e.exclusiveOwnerThread 记录锁的持有

核心方法

tryAcquire ---重试获取锁

tryRelease--释放锁

acquireSharedInterruptibly---将当前线程变为阻塞状态

releaseShared ---让等待的线程,被唤醒 同时状态变为0

AQS为什么头结点是为空的

头结点存储的是获取到锁的线程,当释放锁的时候就将对象置空,方便GC回收,防止浪费内存空间。

模拟AQS的底层写法(LockSupport+CAS的结合实现)核心代码

/**

* 获取锁

*/

public void lock() {

//e=0,n=1 v=0

// 底层使用cas 修改锁的状态从0变为1 硬件层面帮助我们实现

if (acquire()) {

return;

}

// 使用cas 修改锁的状态失败 设计重试次数

Thread currentThread = Thread.currentThread();

// 如果该线程已经存在的情况下

waitThreads.add(currentThread);

for (; ; ) {

//短暂重试

if (acquire()) {

// 移除队列

waitThreads.push(currentThread);

return;

}

// 重试一次还是没有获取到锁,将当前的这个线程变为阻塞状态

LockSupport.park();

}

}

/**

* 释放锁

*/

public void unLock() {

if (exclusiveOwnerThread != Thread.currentThread()) {

throw new RuntimeException("不是当前线程在释放锁");

}

// 释放锁

if (compareAndSetState(1, 0)) {

this.exclusiveOwnerThread = null;

// 取出阻塞的线程 唤醒

Thread pollThread = waitThreads.poll();

if (pollThread != null)

// 唤醒刚才阻塞的线程

LockSupport.unpark(pollThread);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值