java aqs详解_Java AQS底层原理解析

AQS底层原理

AQS(AbstractQueuedSynchronizer)是一个抽象同步队列,JUC(java.util.concurrent)中很多同步锁都是基于AQS实现的。

AQS的基本原理就是当一个线程请求共享资源的时候会判断是否能够成功操作这个共享资源,如果可以就会把这个共享资源设置为锁定状态,如果当前共享资源已经被锁定了,那就把这个请求的线程阻塞住,也就是放到队列中等待。

state变量:

AQS中有一个被volatile声明的变量用来表示同步状态

提供了getState()、setState()和compareAndSetState()方法来修改state状态的值

// 返回同步状态的当前值

protected final int getState() {

return state;

}

// 设置同步状态的值

protected final void setState(int newState) {

state = newState;

}

// CAS操作修改state的值

protected final boolean compareAndSetState(int expect, int update) {

return unsafe.compareAndSwapInt(this, stateOffset, expect, update);

}

对共享资源的操作方式:

上面说了AQS是JUC中很多同步锁的底层实现,锁也分很多种,有像ReentrantLock这样的独占锁,也有ReentrantReadWriteLock这样的共享锁,所以AQS中也必然是包含这两种操作方式的逻辑

独占式

获取资源的时候会调用acquire()方法,这里面会调用tryAcquire()方法去设置state变量,如果失败的话就把当前线程放入一个Node中存入队列

public final void acquire(int arg) {

if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

释放资源的时候是调用realase()方法,会调用tryRelease()方法修改state变量,调用成果后会去唤醒队列中Node里的线程,unparkSuccessor()方法就是判断当前state变量是否符合唤醒的标准,如果合适就唤醒,否则继续放回队列

public final boolean release(int arg) {

if (tryRelease(arg)) {

Node h = head;

if (h != null && h.waitStatus != 0)

unparkSuccessor(h);

return true;

}

return false;

}

注意tryAcquire()和tryRelease()方法在AQS中都是空的,前面说了JUC中很多同步锁都是基于AQS实现,所以加锁和释放锁的逻辑都还不确定,因此是要在这些同步锁中实现这两个方法

protected boolean tryAcquire(int arg) {

throw new UnsupportedOperationException();

}

protected boolean tryRelease(int arg) {

throw new UnsupportedOperationException();

}

共享式

获取资源会调用acquireShared()方法,会调用tryAcquireShared()操作state变量,如果成功就获取资源,失败则放入队列

public final void acquireShared(int arg) {

if (tryAcquireShared(arg) < 0)

doAcquireShared(arg);

}

释放资源是调用releaseShared()方法,会调用tryReleaseShared()设置state变量,如果成功就唤醒队列中的一个Node里的线程,不满足唤醒条件则还放回队列中

public final boolean releaseShared(int arg) {

if (tryReleaseShared(arg)) {

doReleaseShared();

return true;

}

return false;

}

和独占式一样,tryAcquireShared()和tryReleaseShared()也是需要子类来提供

protected int tryAcquireShared(int arg) {

throw new UnsupportedOperationException();

}

protected boolean tryReleaseShared(int arg) {

throw new UnsupportedOperationException();

}

条件变量Condition

Condition中的signal()和await()方法类似与notify()和wait()方法,需要和AQS锁配合使用。

public static void main(String[] args) throws InterruptedException {

ReentrantLock lock = new ReentrantLock();

Condition condition = lock.newCondition();

Thread thread1 = new Thread(new Runnable() {

@Override

public void run() {

lock.lock();

System.out.println(" t1 加锁");

System.out.println("t1 start await");

try {

condition.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("t1 end await");

lock.unlock();

}

});

thread1.start();

Thread thread2 = new Thread(new Runnable() {

@Override

public void run() {

lock.lock();

System.out.println(" t2 加锁");

System.out.println("t2 start signal");

condition.signal();

System.out.println("t2 end signal");

lock.unlock();

}

});

thread2.start();

}

在AQS中的原理

上面lock.newCondition()其实是new一个AQS中ConditionObject内部类的对象出来,这个对象里面有一个队列,当调用await()方法的时候会存入一个Node节点到这个队列中,并且调用park()方法阻塞当前线程,释放当前线程的锁。而调用singal()方法则会移除内部类中的队列头部的Node,然后放入AQS中的队列中等待执行机会

同样的,AQS并没有实现newCondition()方法,也是需要子类自己去实现

总结:

本文内容大部分都是阅读了<>这本书的内容,主要讲了整个AQS的大致原理,和几个最重要的方法,其实整个AQS的源码是很复杂的,但是了解大致原理已经对我们熟悉运用那些JUC中的同步锁有很大的帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328484.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在.NET Core程序中设置全局异常处理

以前我们想设置全局异常处理只需要这样的代码&#xff1a; 1 AppDomain currentDomain AppDomain.CurrentDomain;2 currentDomain.UnhandledException new UnhandledExceptionEventHandler(MyExceptionHandler); 但是在.NET Core中并没有AppDomain的相关实现&#xff0c;至少…

matlab 画柱状图

data [0.1869, 0.1900, 0.1878, 0.1847]; b bar(data); ch get(b,children); set(gca,XTickLabel,{非加权聚类欧氏距离类比,非加权聚类马氏距离类比,加权聚类欧氏距离类比,加权聚类马氏距离类比}) set(ch,FaceVertexCData,[1 1 1;1 1 1;1 1 1;1 1 1;])

java释放线程资源_Java线程之释放锁,释放资源,释放CPU

多线程中的wait与sleep到底谁释放了锁首先&#xff0c;多线程中会使用到两个延迟的函数&#xff0c;wait和sleep。wait是Object类中的方法&#xff0c;而sleep是Thread类中的方法。sleep是Thread类中的静态方法。无论是在a线程中调用b的sleep方法&#xff0c;还是b线程中调用a的…

经典的Java基础面试题集锦

转载自 经典的Java基础面试题集锦问题&#xff1a;如果main方法被声明为private会怎样&#xff1f; 答案&#xff1a;能正常编译&#xff0c;但运行的时候会提示”main方法不是public的”。 问题&#xff1a;Java里的传引用和传值的区别是什么&#xff1f; 答案&#xff1a;传…

聚类中心选取

https://blog.csdn.net/zhihaoma/article/details/48649489 https://www.cnblogs.com/dudumiaomiao/p/5839905.html

Vue.js先入个门看看

使用vue.js原文介绍&#xff1a;Vue.js是一个构建数据驱动的web界面库。Vue.js的目标是通过尽可能简单的API实现响应式数据绑定和组合的视图组件。vue.js上手非常简单&#xff0c;先看看几个例子&#xff1a; 例一&#xff1a;Helloworld html代码&#xff1a; <div id"…

java path 注解_@PathVariable注解的使用和@Requestparam

一、 PathVariablePathVariable这是一个路径映射格式的书写方式注解&#xff0c;在类映射路径的后加上/{对应方法参数中属性PathVariable("code")中的code}&#xff0c;SuppressWarnings({ "unchecked", "rawtypes" })RequestMapping(value &qu…

近5年133个Java面试题 你会几个?

https://blog.csdn.net/fireblue1990/article/details/73695121 http://www.ablanxue.com/shtml/201608/33470_1.shtml

精选30道Java笔试题解答

转载自 精选30道Java笔试题解答 1. 下面哪些是Thread类的方法&#xff08;&#xff09; A start() B run() C exit() D getPriority() 答案&#xff1a;ABD 解析&#xff1a;看Java API docs吧&#xff1a;http://docs.oracle.com/javase/7/docs/ap…

.NET Core 1.0.1 发布了

今天微软发布了 .NET Core 1.0.1&#xff0c;这是 .NET Core 1.0 的首个微软长期支持更新&#xff0c;同时发布的还有 ASP.NET Core 1.0.1 与 Entity Framework Core 1.0.1。 .NET Core 1.0.1 中的主要更新与 bug 修复&#xff1a; Segfaults on Linux 4.6 – coreclr 6016; co…

java this用法_java中this用法小结

Java关键字this只能用于方法方法体内。当一个对象创建后&#xff0c;Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针&#xff0c;这个指针的名字就是this。因此&#xff0c;this只能在类中的非静态方法中使用&#xff0c;静态方法和静态的代码块中绝对不能出现this,并且…

第1步 新建spring+springmvc+mybatis项目 每步都有 讲解 巨详细

Idea2017部署项目到tomcat时没有artifacts解决办法 2017年12月01日 23:16:22 剑胜 阅读数&#xff1a;10342 在Idea2017中想部署maven构建的项目到tomcat容器中时&#xff0c;需要配置Deployment属性&#xff0c;选择war或者war exploded的发布方式。而要进行这个配置首先要点…

Java 集合系列04之 fail-fast总结

转载自 Java 集合系列04之 fail-fast总结概要 前面&#xff0c;我们已经学习了ArrayList。接下来&#xff0c;我们以ArrayList为例&#xff0c;对Iterator的fail-fast机制进行了解。内容包括&#xff1a;&#xff1a;1 fail-fast简介2 fail-fast示例3 fail-fast解决办法4 fai…

Vue.js说说组件

什么是组件&#xff1a;组件是Vue.js最强大的功能之一。组件可以扩展HTML元素&#xff0c;封装可重用的代码。在较高层面上&#xff0c;组件是自定义的元素&#xff0c;Vue.js的编译器为它添加特殊功能。在有些情况下&#xff0c;组件也可以是原生HTML元素的形式&#xff0c;以…

java 内存快照怎么看_jvm内存快照dump文件太大,怎么分析

1、场景通常&#xff0c;使用eclipse的mat图形化工具打开dump的时候都会内存溢出.对于比较小的dump&#xff0c;eclipse可以打开&#xff0c;但一旦dump文件太大&#xff0c;eclipse就有点束手无策。这时候怎么办呢&#xff1f;可以使用linux下的mat&#xff0c;既Memory Analy…

第3步 (请先看第2步再看第3步) 新建完spring+springmvc+mybatis项目 需要推送gitee仓库进行管理 巨详细

idea中Terminal终端无法执行GIT命令&#xff1a; touch README.md问题解决 解决方法二&#xff1a; ◆更改路径即可 Git\bin\bash.exe 或 Git\bin\sh.exe 然后重新启动idea即可 ********************88注意&#xff1a;每次更改完成后需要重新启动IDEA****************** 记…

115个Java面试题和答案——终极列表(下)

转载自 115个Java面试题和答案——终极列表&#xff08;下&#xff09;第一篇讨论了面向对象编程和它的特点&#xff0c;关于Java和它的功能的常见问题&#xff0c;Java的集合类&#xff0c;垃圾收集器&#xff0c;本章主要讨论异常处理&#xff0c;Java小应用程序&#xff0…

java编译提示错误信息_JAVA编译错误提示缺少“{”

展开全部有点粗心了 我把我修改过的发62616964757a686964616fe58685e5aeb931333335323435给你具体问题&#xff1a;是extends不是extands类Circle拼错Circle构造方法height拼错abstract class Shape{public int width,height;public Shape(int width,int height){this.widthwid…

谈谈这些年前端的变化

我从事web开发工作到现在差不多四年了&#xff0c;前后台都涉及过&#xff0c;近两年两年前端开发为主。我记得11年的时候&#xff0c;我到南京的第一年&#xff0c;加入了一个电商公司&#xff0c;从事PHP开发&#xff0c;那个时候公司里面有一个女孩子&#xff0c;专门从事前…

第2步 安装git 配置git用户 git的安装和项目的建立

安装git 比较简单 在window上是有个 git bash 这个命令集成了一部分window和linux的命令 在任意目录下(一般是项目工程目录下面) 右键点击git bash 进入之后 小写字母 i 进入编辑模式&#xff08;insert模式出入&#xff09; [user] nameyjb1091947832(注册…