当前位置:网站首页>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
边栏推荐
- Intuitive understanding of the essence of two-dimensional rotation
- Comment créer un pass BEP - 20 sur la chaîne BNB
- 【文本分类案例】(4) RNN、LSTM 电影评价倾向分类,附TensorFlow完整代码
- 数据库查询 - 选课系统
- [webrtc] add x264 encoder for CEF / Chromium
- NiO related Basics
- Class loading process of JVM
- Is meituan, a profit-making company with zero foundation, hungry? Coupon CPS applet (with source code)
- Audio editing generation software
- 【2022】将3D目标检测看作序列预测-Point2Seq: Detecting 3D Objects as Sequences
猜你喜欢
基于pytorch搭建GoogleNet神经网络用于花类识别
5 minutes to achieve wechat cloud applet payment function (including source code)
精简CUDA教程——CUDA Driver API
Grafana shares links with variable parameters
C6748 软件仿真和硬件测试 ---附详细FFT硬件测量时间
Shanda Wangan shooting range experimental platform project - personal record (IV)
The most detailed network counting experiment in history (2) -- rip experiment of layer 3 switch
如何在BNB链上创建BEP-20通证
LeetCode异或运算
山东大学软件学院项目实训-创新实训-网络安全靶场实验平台(七)
随机推荐
[2022] regard 3D target detection as sequence prediction - point2seq: detecting 3D objects as sequences
Hot reload debugging
MySQL数据库 - 数据库和表的基本操作(二)
山大网安靶场实验平台项目-个人记录(五)
Summary of several relationships of UML class diagram
MFC获取本机IP(网络通讯时用得多)
Audio editing generation software
VeraCrypt文件硬盘加密使用教程
Common processing of point cloud dataset
Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies
Mysql database - connection query
如何在BNB鏈上創建BEP-20通證
C6748 软件仿真和硬件测试 ---附详细FFT硬件测量时间
Class loading mechanism
一个简单的(基于redisson的)分布式同步工具类封装
Project training of Software College of Shandong University - Innovation Training - network security shooting range experimental platform (VII)
渤海期货这家公司怎么样。期货开户办理安全?
Electron入门教程3 ——进程通信
Lottery applet, mother no longer have to worry about who does the dishes (assign tasks), so easy
Go modules daily use