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 ...
随机推荐
- linux学习之路(4)
用户身份与文件权限 通过uid来区分: 管理员 UID 为 0:系统的管理员用户. 系统用户 UID 为 1-999: Linux 系统为了避免因某个服务程序出现漏洞而被黑客提 权至整台服务器,默认 ...
- 一套最全的JavaScript 语言基础知识点总结(思维导图10张)
1.DOM基础操作 2.数组基础 3.函数基础 4.运算符 5.流程控制语句 6.正则表达式 7.字符串函数 8.数据类型 9.变量 10.window对象
- 「Luogu 1471」 方差
题目背景 滚粗了的HansBug在收拾旧数学书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差. 输入输出 ...
- 「BZOJ 2733」「HNOI 2012」永无乡「启发式合并」
题意 你需要维护若干连通快,有两个操作 合并\(x,y\)所在的连通块 询问\(x\)所在连通块中权值从小到大排第\(k\)的结点编号 题解 可以启发式合并\(splay\),感觉比较好些的 一个连通 ...
- The server of Nginx(一)——Nginx基础及静态网站的构建
一.Nginx介绍 火了半边天的Nginx和Apache一样也是Web服务器,专为性能优化而开发,也可以像Squid一样做反向代理,或者邮件代理等许多用途,并有windows的移植版,其最知名的优点是 ...
- linux 下系统时间设置C语言实现
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h&g ...
- Qt 学习之路 2(27):渐变
Qt 学习之路 2(27):渐变 豆子 2012年11月20日 Qt 学习之路 2 17条评论 渐变是绘图中很常见的一种功能,简单来说就是可以把几种颜色混合在一起,让它们能够自然地过渡,而不是一下子变 ...
- 移动端适配1px问题
(function(document) { var dcl = document.documentElement, wh; var scale = 1/window.devicePixelRatio; ...
- Linux之vi三种模式常用操作
vi的三种模式:命令模式.编辑模式.尾行模式 一.命令模式 1.光标移动 a.字符级 左(h) 下(j) 上(k) 右(l) b.单词级 w word移动到下个单词首字母 b before上个单词首字 ...
- 极限编程(xp),iso国际标准化组织
极限编程(xp):eXtreme Programming 极限编程-XP 四个价值:沟通 communication.简化 similicity.反馈 feedback.勇气 courage http ...