当前位置:网站首页>aqs的学习
aqs的学习
2022-04-23 19:47:00 【Fairy要carry】
目录
概述:

通过继承它来实现父类的功能

获取锁:

阻塞和获取资源用的是park和unpark;
释放锁:

判断是否有锁资源:
AbstractQueuedSynchronizer公有方法(AQS)
1.acquire:独占式获取同步状态;
2.release:独占式释放同步状态;
3.acquireShared(int arg):
共享式获取同步状态,如果当前线程未获取到同步状态,那么就进队列等待——>与独占式的主要区别是在同一时刻可以有多个线程获取同步状态;
4.releaseShared(int arg):共享式释放同步状态;
需要由子类实现的保护方法
1.tryAcquire:独占式获取同步状态;——通过cas操作设置锁资源占有状态,并且对锁的Owner进行设置
2.tryRelease:独占式释放同步状态;

3.getState:返回锁状态

还有几个shared
其他方法

锁和同步器的区别
锁:面向使用者,定义了锁和使用者交互方式 ,隐藏了细节;
同步器:面向的是锁的实现者,简化了锁的实现方式;
锁和同步器很好的隔离了使用者和实现着所需要关注的领域;
自定义锁-独占锁
package com.example.juc.AQS;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import static java.lang.Thread.sleep;
/**
* @author diao 2022/4/23
*/
@Slf4j(topic = "c.TestAqs")
public class TestAqs {
public static void main(String[] args) {
MyLock lock = new MyLock();
new Thread(()->{
lock.lock();
log.debug("locking...");
lock.lock();//synchronized和ReentrantLock都是可重入
try {
log.debug("locking...");
sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
log.debug("unlocking...");
lock.unlock();
}
},"t1").start();
// new Thread(()->{
// lock.lock();
// try {
// log.debug("locking...");
// } finally {
// log.debug("unlocking...");
// lock.unlock();
// }
// },"t2").start();
}
}
//自定义锁(不可重入锁);可重入锁:拿到锁资源下次进入一样可以进入
class MyLock implements Lock{
//独占锁,AQS基于队列(同步器)
class MySync extends AbstractQueuedSynchronizer{
/*1.尝试获取锁资源*/
@Override
protected boolean tryAcquire(int arg) {
//因为可能会有多个线程竞争锁资源,所以要进行cas
if(compareAndSetState(0,1)){
//尝试将锁的owner设置为当前线程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
/*2.尝试释放锁资源*/
@Override
protected boolean tryRelease(int arg) {
//这里需要注意顺序,setState有volatile字段
// 有读写屏障,前面的修改锁拥有资源对其他线程都可见
setExclusiveOwnerThread(null);
setState(0);
return true;
}
/*3.判断是否持有独占锁*/
@Override
protected boolean isHeldExclusively() {
return getState()==1;
}
public Condition newCondition(){
return new ConditionObject();
}
}
private MySync sync=new MySync();
@Override//加锁(不成功,会进入等待队列)
public void lock() {
sync.acquire(1);
}
@Override//加锁,可打断
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override//尝试加锁,带超时
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1,unit.toNanos(time));
}
@Override//解锁
public void unlock() {
/**
* 和sync中的tryRelease是不一样的
* 上面的只是改变锁的拥有者以及锁的state,但并不会唤醒被阻塞的线程
* release可唤醒阻塞线程
*/
sync.release(1);
}
@Override//返回条件变量
public Condition newCondition() {
return sync.newCondition();
}
}
![]()
如代码所示,独占锁实现了在同一时刻只能用一个线程获取到锁,而其他获取锁的线程只能在等待队列等待;
AQS小结
使用方式?
AQS主要是通过继承的方式,子类通过继承同步器并实现它的抽象方法->来管理同步状态;
如何管理同步状态?
AQS使用一个int类型的成员变量state来表示同步状态,当state>0时表示已经获取了锁,当state = 0时表示释放了锁。它提供了三个方法(getState()、setState(int newState)、compareAndSetState(int expect,int update))来对同步状态state进行操作,当然AQS可以确保对state的操作是安全的。
特点:
AQS通过内置的FIFO同步队列来完成资源获取线程的排队工作,如果当前线程获取同步状态失败时,AQS则会将当前线程以及等待状态等信息构造成一个节点(Node)并将其加入同步队列,同时会阻塞当前线程;
站在使用角度,我理解其实就两个功能:独占和共享,要么独占要么共享,然后调用底层api;
AQS的大致实现思路
AQS内部维护了一个CLH队列来管理锁。线程会首先尝试获取锁,如果失败就将当前线程及等待状态等信息包装成一个node节点加入到同步队列sync queue里。 接着会不断的循环尝试获取锁(自旋),条件是当前节点为head的直接后继才会尝试。如果失败就会阻塞自己直到自己被唤醒。而当持有锁的线程释放锁的时候,会唤醒队列中的后继线程。
CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。
版权声明
本文为[Fairy要carry]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_57128596/article/details/124364671
边栏推荐
猜你喜欢

基于pytorch搭建GoogleNet神经网络用于花类识别

C6748 software simulation and hardware test - with detailed FFT hardware measurement time

Building googlenet neural network based on pytorch for flower recognition

【文本分类案例】(4) RNN、LSTM 电影评价倾向分类,附TensorFlow完整代码

5 minutes to achieve wechat cloud applet payment function (including source code)

Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies

Mfcc: Mel frequency cepstrum coefficient calculation of perceived frequency and actual frequency conversion
![[report] Microsoft: application of deep learning methods in speech enhancement](/img/c1/7bffbcecababf8dabf86bd34ab1809.png)
[report] Microsoft: application of deep learning methods in speech enhancement

【webrtc】Add x264 encoder for CEF/Chromium

【webrtc】Add x264 encoder for CEF/Chromium
随机推荐
【2022】将3D目标检测看作序列预测-Point2Seq: Detecting 3D Objects as Sequences
深度学习——特征工程小总结
Grafana 分享带可变参数的链接
Compact CUDA tutorial - CUDA driver API
Software College of Shandong University Project Training - Innovation Training - network security shooting range experimental platform (8)
Mysql database - basic operation of database and table (II)
程序设计语言基础(2)
Project training of Software College of Shandong University - Innovation Training - network security shooting range experimental platform (V)
An example of using JNI to directly access surface data
Prefer composition to inheritance
山东大学软件学院项目实训-创新实训-网络安全靶场实验平台(七)
VeraCrypt文件硬盘加密使用教程
Scrum Patterns之理解各种团队模式
MySQL数据库 - 单表查询(一)
Lottery applet, mother no longer have to worry about who does the dishes (assign tasks), so easy
Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies
Esp8266 - beginner level Chapter 1
The textarea cursor cannot be controlled by the keyboard due to antd dropdown + modal + textarea
TI DSP的 FFT与IFFT库函数的使用测试
JVM的类加载过程