java aqs源码_java中AQS源码分析

AQS内部采用CLH队列。CLH队列是由节点组成。内部的Node节点包含的状态有

static final int CANCELLED =  1;

static final int SIGNAL    = -1;

static final int CONDITION = -2;

static final int PROPAGATE = -3;

其中取消状态表示任务的取消,SIGNAL状态表示后续节点需要唤醒,CONDITION表示等待状态,PROPAGRATE表示的是传播状态通常用于共享锁的释放。初始节点的状态为0。

AQS中比较重要的操作包括:

public final void acquire(int arg);

public final void acquireInterruptibly(int arg);

public final void acquireShared(int arg);

public final void acquireSharedInterruptibly(int arg);

protected boolean tryAcquire(int arg);

protected int tryAcquireShared(int arg);

public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException;

public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException;

其中:public final void acquire(int arg) {

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

selfInterrupt();

}

其中tryAcquire方法为抽象方法。不同的子类有不同的实现方式。AQS中该方法的实现知识抛出了一个异常。

final boolean acquireQueued(final Node node, int arg) {

boolean failed = true;//标记是否成功拿到资源

try {

boolean interrupted = false;//标记等待过程中是否被中断过

//自旋的过程

for (;;) {

final Node p = node.predecessor();//拿到前驱

//如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。

if (p == head && tryAcquire(arg)) {

setHead(node);//拿到资源后,将head指向该结点。所以head所指的标杆结点,就是当前获取到资源的那个结点或null。

p.next = null; // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了!

failed = false;

return interrupted;//返回等待过程中是否被中断过

}

//如果自己可以休息了,就进入waiting状态,直到被unpark()

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;//如果等待过程中被中断过,哪怕只有那么一次,就将interrupted标记为true

}

} finally {

if (failed)

cancelAcquire(node);

}

}

可以从该方法中看出。这里会继续尝试去获取一下资源

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {

int ws = pred.waitStatus;//拿到前驱的状态

if (ws == Node.SIGNAL)

//如果已经告诉前驱拿完号后通知自己一下,那就可以安心休息了

return true;

if (ws > 0) {

/*

* 如果前驱放弃了,那就一直往前找,直到找到最近一个正常等待的状态,并排在它的后边。

* 注意:那些放弃的结点,由于被自己“加塞”到它们前边,它们相当于形成一个无引用链,稍后就会被保安大叔赶走了(GC回收)!

*/

do {

node.prev = pred = pred.prev;

} while (pred.waitStatus > 0);

pred.next = node;

} else {

//如果前驱正常,那就把前驱的状态设置成SIGNAL,告诉它拿完号后通知自己一下。有可能失败,人家说不定刚刚释放完呢!

compareAndSetWaitStatus(pred, ws, Node.SIGNAL);

}

return false;

}

在该方法中会检测当前节点中前面的节点是否有CANCELLED状态的如果有。待会儿后续的操作这些节点会被GC回收。

如果一切正常当前节点的前一个节点会被设置为SIGNAL状态。

1 private final boolean parkAndCheckInterrupt() {

2     LockSupport.park(this);//调用park()使线程进入waiting状态

3     return Thread.interrupted();//如果被唤醒,查看自己是不是被中断的。

4 }

线程进入waiting状态。线程被唤醒的方式有被unpark和被中断。

public final boolean release(int arg) {

if (tryRelease(arg)) {

Node h = head;//找到头结点

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

unparkSuccessor(h);//唤醒等待队列里的下一个线程

return true;

}

return false;

}

这里tryRelease也是一个抽象方法不同的子类有不同的实现。

private void unparkSuccessor(Node node) 内部首先会设置当前节点的状态为初始状态。同时找到一个有效的后继节点的状态小于0的进行节点的释放。 LockSupport.unpark(s.thread);//唤醒对应的线程。

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

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

相关文章

android4.0.3去掉底部状态栏statusbar,全屏显示示例代码

要去掉android4.0上的状态栏,全屏显示的代码如下: 1、将usleep和killall这二个文件放到assets文件夹下。这二个文件可在下面的附件中下载到。 2、创建Device.java(注:附件里有完整的代码): 001import java.io.Buf…

[译]预留位置队列PRQueue:多线程程序中消息输入队列和消息输出队列保持同序...

译自: http://accu.org/var/uploads/journals/overload101.pdf 在多线程应用程序中,要求消息输入队列和消息输出队列顺序要求保持一致,而忽略多线程并发处理的顺序,这种情况是比较难处理的。在本文中,作者设计了一种新…

java 前端工作内容_java前端、java后端、java全栈工作主要内容是什么?哪个薪资高?...

摘要最近,听了一场关于java全栈工程师职位的简介说明,里面很清楚的说明了一下前端,后端,全栈都是做什么工作的。其实,想做这个行业,就应该了解职能以及技能需求,这样学习才能更高效。我知道一些…

用yate2实现软VoIP语音通话(SIP协议)

用yate2实现软VoIP语音通话(SIP协议) 阳光男孩 发表于 2009-01-08 2009年1月7日,工业与信息化部发放了三张3G牌照,标志着中国进入了通信技术的新时代。3G的重要特性之一是高速数据链路,移动上网速度大大提高。同时,中国移动也大…

避免頁面重復提交3/15

在用戶做資料錄入操作時時常會反映重復記錄出現,經過了解是針對新手或者性子急的用戶在儲存時多次點擊引起 有效處理方法:新增一textbox,對儲存按鈕的onclick增設js代碼:btnsave.Attributes.Add("onclick", "var tb15document.getElementById(Textbox15);var nu…

java 日志设计_Java日志设计实践(3) - 开发篇

1.选择恰当的日志级别2.输出明确的提示文字和充分的现场信息3.输出内容一行搞定,不要换行4.其他1.选择恰当的日志级别选择日志级别时需要遵循一些通用规范,不可随意定义log4j的日志级别,由低到高排列:all trace debug info warn e…

ConfigurationManager.AppSettings[] ConfigurationManager智能显示不出来

解决办法:在项目中添加System.Configuration引用。转载于:https://www.cnblogs.com/2008freestyle/archive/2012/03/15/2398046.html

java5的递归算法_java递归算法 java面试题(5)

Java语言是一种具有动态性的解释型语言,类(class)只有被加载到JVM后才能运行。当运行指定程序时,JVM会将编译生成的.class文件按照需求和一定的规则加载到内存中,并组织成为一个完整的Java应用程序。这个加载过程是由类加载器完成&#xff0c…

OpenGL ES 2.0 for iPhone Tutorial

来源:http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial If youre new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting! Learn how to use OpenGL ES 2.0 from the ground up! OpenGL ES is th…

java种子填充_种子填充实例运行出问题

种子填充实例运行出问题import java.awt.*;import java.applet.*;import java.awt.image.ImageProducer;import java.awt.image.MemoryImageSource;import java.util.Stack;public class scanseed extends Applet {private static final long serialVersionUID 1L;int redColo…

Mdi悬浮子窗体不超过主窗体边界

//1.设置父窗体(主窗体)的AutoScrollMinSize大于父窗体的Size//例如主窗体(400,400), AutoScrollMinSize(500,500)//2.设置主窗体的IsMdiContainer为true private void Form2_Load(object sender, EventArgs e) {//悬浮窗体 Form3 f3 new Form3();//…

Ubuntu 12.04 root用户登录设置

Ubuntu 12.04默认是不允许root登录的,在登录窗口只能看到普通用户和访客登录。以普通身份登陆Ubuntu后我们需要做一些修改,普通用户登录后,修改系统配置文件需要切换到超级用户模式,在终端窗口里面输入: sudo -s.然后输入普通用户登陆的密码&#xff0c…

java codepointbefore_Java StringBuilder codePointBefore()方法与示例

StringBuilder类codePointBefore()方法codePointBefore()方法在java.lang包中可用。codePointBefore()方法用于表示给定索引和数组索引从0到length()-1开始的Unicode代码点。codePointBefore()方法是一种非静态方法,仅可通过类对象访问,如果尝试使用类名…

随机交换检验数据挖掘结果-assessing data mining result via swap randomization

转载自己的博客: http://blog.csdn.net/lgnlgn/article/details/5936945 数据挖掘中一个重要的研究议题是确定发现的模式或模型是否显著。虽然传统统计方法已经早已用以进行显著性检验,但是在数据挖掘领域这一方法却没有得到足够的重视。在本文中提出采…

sip中的100trying到底有啥用

SIP是一种类似HTTP的基于请求响应的协议。理想情况下,请求被发出后,应该无任何延迟的传回响应。但是这是理想情况,有些时候接收端收到请求后进行处理需要一定的延迟,这个延迟是不一定的,SIP中有一个超时机制&#xff0…

java幂等性原理_Java接口幂等性设计原理解析

在微服务架构下,我们在完成一个订单流程时经常遇到下面的场景:一个订单创建接口,第一次调用超时了,然后调用方重试了一次在订单创建时,我们需要去扣减库存,这时接口发生了超时,调用方重试了一次…

intent几种传值数组、对象、集合(Array,Object,List)

1.Array private ArrayList<String> checkListnew ArrayList<String>();Intent intentnew Intent(mytext.this,show.class);intent.putStringArrayListExtra("list", checkList);startActivity(intent);调用 Intent intentthis.getIntent();ArrayList&l…

.mod.c 是什么文件

我们可以为代码清单4.1的模板编写一个简单的Makefile&#xff1a; obj-m : hello.o 并使用如下命令编译Hello World模块&#xff1a; make -C /usr/src/linux-2.6.15.5/ M/driver_study/ modules 如果当前处于模块所在的目录&#xff0c;则以下命令与上述命令同等&#xff1a…

java web Jersey_使用CXF和Jersey框架来进行Java的WebService编程

CXFCXF是在xfire的基础上实现的。1)首先呢&#xff0c;还是包的问题&#xff0c;在http://cxf.apache.org/download.html这里可以下到最新版的CXF&#xff0c;当然&#xff0c;我用的是最新版的。接下来还是那句废话&#xff0c;建WEB项目&#xff0c;放入JAR包。而JAR包我们就…

Binding是WPF的核心,WPF的常用数据源绑定有四种

Binding是WPF的核心&#xff0c;WPF的数据源有以下几种&#xff1a; 1、ADO.NET中的DataTable 2、xml数据源 3、object数据源 4、元素控件属性 详细说明见链接&#xff1a;http://www.cnblogs.com/linlf03/archive/2011/09/06/2168440.html 转载于:https://www.cnblogs.com/jun…