当前位置:网站首页>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
边栏推荐
- Kubernetes introduction to mastery - ktconnect (full name: kubernetes toolkit connect) is a small tool based on kubernetes environment to improve the efficiency of local test joint debugging.
- The difference between underline and dot of golang import package
- 数据库查询 - 选课系统
- Codeworks round 783 (Div. 2) d problem solution
- MySQL数据库 - 单表查询(二)
- goroutine
- Leetcode XOR operation
- Design of library management database system
- 如何在BNB鏈上創建BEP-20通證
- 对普通bean进行Autowired字段注入
猜你喜欢

Kubernetes入门到精通-KtConnect(全称Kubernetes Toolkit Connect)是一款基于Kubernetes环境用于提高本地测试联调效率的小工具。

2021-2022-2 ACM training team weekly Programming Competition (8) problem solution

Mfcc: Mel frequency cepstrum coefficient calculation of perceived frequency and actual frequency conversion

Scrum Patterns之理解各种团队模式

山东大学软件学院项目实训-创新实训-网络安全靶场实验平台(七)

【文本分类案例】(4) RNN、LSTM 电影评价倾向分类,附TensorFlow完整代码
![[报告] Microsoft :Application of deep learning methods in speech enhancement](/img/c1/7bffbcecababf8dabf86bd34ab1809.png)
[报告] Microsoft :Application of deep learning methods in speech enhancement

【webrtc】Add x264 encoder for CEF/Chromium

Distinction between pointer array and array pointer

命令-sudo
随机推荐
uIP1. 0 actively sent problem understanding
Mfcc: Mel frequency cepstrum coefficient calculation of perceived frequency and actual frequency conversion
Introduction to electron Tutorial 4 - switching application topics
MySQL lock
Redis core technology and practice 1 - start with building a simple key value database simplekv
Database query - course selection system
什么是消息队列
Kubernetes entry to mastery - bare metal loadbalance 80 443 port exposure precautions
Comment créer un pass BEP - 20 sur la chaîne BNB
Distinction between pointer array and array pointer
LeetCode异或运算
C语言的十六进制printf为何输出有时候输出带0xFF有时没有
Virtual machine performance monitoring and fault handling tools
Deep learning -- Summary of Feature Engineering
指针数组与数组指针的区分
Inject Autowired fields into ordinary beans
Electron入门教程3 ——进程通信
MySQL advanced lock - overview of MySQL locks and classification of MySQL locks: global lock (data backup), table level lock (table shared read lock, table exclusive write lock, metadata lock and inte
【数值预测案例】(3) LSTM 时间序列电量预测,附Tensorflow完整代码
Decompile and get the source code of any wechat applet - just read this (latest)