AQS的数据结构及实现原理
int waitStatus
|
等待状态:
1 ,在队列中等待的线程等待超时或者被中断,从队列中取消等待;
-1,后继节点处于等待;
-2,节点在等待队列中,当condition被signal()后,会从等待队列转到同步队列;
-3,表示下一次共享式同步状态获取将会被无条件传播下去;
0,初始状态
|
Node prev
|
前驱节点
|
Node next
|
后继节点
|
Node nextWaiter
|
等待队列中的后继节点,如果当前节点是共享的,则这个字段将是一个SHARED常量,也就是说节点类型(独占或共享)和等待队列中的后继节点共用同一字段
|
Thread thread
|
获取同步状态的线程
|


- public final void acquire(int arg) {
- if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
- selfInterrupt();
- }
- final boolean acquireQueued(final Node node, int arg) {
- boolean failed = true;
- try {
- boolean interrupted = false;
- for (;;) {
- final Node p = node.predecessor(); //获取当前节点的前节点
- if (p == head && tryAcquire(arg)) { // 前节点为head,并且自己获取同步成功,说明前节点线程已经执行结束
- setHead(node); //既然前节点的线程结束了,那就把自己设为head节点
- p.next = null; // help GC //断开前节点,便于回收
- failed = false;
- return interrupted;
- }
- if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) //这里会将线程挂起
- interrupted = true;
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
- public final boolean release(int arg) {
- if (tryRelease(arg)) {
- Node h = head;
- if (h != null && h.waitStatus != 0)
- unparkSuccessor(h); //唤醒后继节点的操作在这里
- return true;
- }
- return false;
- }
- public final void acquireShared(int arg) {
- if (tryAcquireShared(arg) < 0) //小于0,说明没获取成功
- doAcquireShared(arg); //继续获取
- }
- private void doAcquireShared(int arg) {
- final Node node = addWaiter(Node.SHARED); //节点类型为共享类型
- boolean failed = true;
- try {
- boolean interrupted = false;
- for (;;) {
- final Node p = node.predecessor(); //尾节点的前一个节点(当前节点就是尾节点)
- if (p == head) { //前节点是head,则再次获取锁
- int r = tryAcquireShared(arg); // 这个tryAcquireShared()的返回值是共享资源的剩余量,就是还可以允许访问的线程数
- if (r >= 0) { //如果获取到了锁,进行相关设置
- setHeadAndPropagate(node, r); // 进行head节点替换,并且如果剩余量有剩余,则继续往下传递
- p.next = null; // help GC
- if (interrupted)
- selfInterrupt();
- failed = false;
- return;
- }
- }
- if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) //没获取到锁,则将线程挂起
- interrupted = true;
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
- private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
- if (nanosTimeout <= 0L)
- return false;
- final long deadline = System.nanoTime() + nanosTimeout;
- final Node node = addWaiter(Node.EXCLUSIVE); //节点类型是独占式的
- boolean failed = true;
- try {
- for (;;) {
- final Node p = node.predecessor();
- if (p == head && tryAcquire(arg)) { //前节点为head,则尝试获取锁
- setHead(node);
- p.next = null; // help GC
- failed = false;
- return true;
- }
- nanosTimeout = deadline - System.nanoTime(); // 计算剩余时间
- if (nanosTimeout <= 0L) // 剩余时间已经到了
- return false;
- if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) //没获取到锁,时间也没到,则挂起一小段时间。注意如果时间剩余非常小了,比spinForTimeoutThreshold还小,则不挂起了,直接死循环一小会儿,进行获取锁
- LockSupport.parkNanos(this, nanosTimeout);
- if (Thread.interrupted())
- throw new InterruptedException();
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
- public class TwinsLock implements Lock {
- private final Sync sync ;
- private static final class Sync extends AbstractQueuedSynchronizer{
- Sync(int count){
- if(count <= 0){
- throw new IllegalArgumentException("count must large than zero .");
- }
- setState(count); // 这里可以看到,count就是可重入的线程数
- }
- public int tryAcquireShared(int reduceCount){
- for(;;){
- int current = getState();
- int newCount = current - reduceCount;
- if(newCount < 0 || compareAndSetState(current, newCount)){//能把数量减掉并设置,就相当于获取锁成功
- return newCount;
- }
- }
- }
- public boolean tryReleaseShared(int returnCount){
- for(;;){
- int current = getState();
- int newCount = current + returnCount;
- if(compareAndSetState(current, newCount)){
- return true;
- }
- }
- }
- }
- public TwinsLock (int count){
- this.sync = new Sync(count);
- }
- @Override
- public void lock() {
- sync.acquireShared(1);
- }
- @Override
- public void unlock() {
- sync.releaseShared(1);
- }
- // 其它方法
- }
- public class SharedTest {
- private int count = 0;
- private final TwinsLock twinsLock = new TwinsLock(1);
- @Test
- public void test(){
- MyThread mt1 = new MyThread();
- MyThread mt2 = new MyThread();
- MyThread mt3 = new MyThread();
- MyThread mt4 = new MyThread();
- MyThread mt5 = new MyThread();
- mt1.start();
- mt2.start();
- mt3.start();
- mt4.start();
- mt5.start();
- try {
- mt1.join();
- mt2.join();
- mt3.join();
- mt4.join();
- mt5.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("最终结果:" + count);
- }
- class MyThread extends Thread{
- @Override
- public void run() {
- for(int i=0;i<1000;i++){
- twinsLock.lock();
- try {
- count = count + 1;
- }catch (Exception e){
- System.out.println("异常啦 ~ ~ " +e.getMessage());
- }finally {
- twinsLock.unlock();
- }
- }
- }
- }
- }

AQS的数据结构及实现原理的更多相关文章
- Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理
前言 在 Java 中通过锁来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关 ...
- MySQL索引背后的数据结构及算法原理【转】
本文来自:张洋的MySQL索引背后的数据结构及算法原理 摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持 ...
- MySQL 索引背后的数据结构及算法原理
本文转载自http://blog.jobbole.com/24006/ 摘要本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引 ...
- MySQL索引背后的数据结构及算法原理 (转)
摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...
- MySQL(二)索引背后的数据结构及算法原理
本文转载自CodingLabs,原文链接 MySQL索引背后的数据结构及算法原理 目录 摘要 一.数据结构及算法基础 1. 索引的本质 2. B-Tree和B+Tree 3. 为什么使用B-Tree( ...
- CodingLabs - MySQL索引背后的数据结构及算法原理
原文:CodingLabs - MySQL索引背后的数据结构及算法原理 首页 | 标签 | 关于我 | +订阅 | 微博 MySQL索引背后的数据结构及算法原理 作者 张洋 | 发布于 2011-10 ...
- MySQL索引之数据结构及算法原理
MySQL索引之数据结构及算法原理 MySQL支持多个存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.本文只关注BTre ...
- 一文搞懂AQS及其组件的核心原理
@ 目录 前言 AbstractQueuedSynchronizer Lock ReentrantLock 加锁 非公平锁/公平锁 lock tryAcquire addWaiter acquireQ ...
- 【转】MySQL索引背后的数据结构及算法原理
摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...
随机推荐
- Js杂谈-单体模式
单体模式的思想:保证一个特定类仅有一个实例,意味着第二次使用同一个类创建新对象的时候,应该得到与第一次所创建对象完全相同的对象. 下面举几个实现的例子 1.new操作符 这种思想在于当使用同一个构造函 ...
- C#多线程编程实战1.3等待线程
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...
- http服务 WCF、Web API、Web service、WCF REST之间的区别
http服务 WCF.Web API.Web service.WCF REST之间的区别 在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web ...
- 洛谷P2756 飞行员配对方案问题(二分图匹配)
传送门 一个基础的二分图匹配(虽然今天才学会) 因为不会匈牙利算法只好用网络流做 先新建一个超级源和超级汇,源往所有左边的点连边,所有右边的点往汇连边 然后跑一边最大流就好了 顺便记录一下匹配到谁就好 ...
- [Swift]八大排序算法(一):冒泡排序
排序分为内部排序和外部排序. 内部排序:是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列. 外部排序:指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存 ...
- Ping命令简单报错介绍
了解ABC类IP地址:网络.主机.子网.广播. ---------------------------- 学会ping: ping www.baidu.com 网络检测:ping某一主机可以正常启动! ...
- python3+Django1.11+mysql5.7 MySQL DB API Drivers
The Python Database API is described in PEP 249. MySQL has three prominent drivers that implement th ...
- 扩展jQuery高亮网页中的文本选中
<script type="text/javascript"> //1.扩展jQuery $.fn.selectRange = function (start, end ...
- Python闭包需要注意的问题
定义 python中的闭包从表现形式上定义为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure),也就是说内层函数引用了外层函数 ...
- Android 对话框的应用1
1.介绍 2.作用 (1)消息提示对话框 (2)简单列表对话框 (3)单选列表对话框 (4)多选对话框 (5)自定义对话框 3.java后台代码 package com.lucky.test28dia ...