同步队列结构

AQS使用的同步队列是基于一种CLH锁算法来实现。

CLH锁也是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋.

同步器中包含了两个节点类型的引用,一个指向头节点(head),一个指向尾节点(tail),没有获取到锁的线程,加入到队列的过程必须保证线程安全,因此同步器提供了一个基于CAS的设置尾节点的方法CompareAndSetTail(Node expect,Node update),它需要传递当前线程认为的尾节点和当前节点,只有设置成功后,当前节点才能正式与之前的尾节点建立关联。

同步器队列遵循FIFO,首节点是获取锁成功的节点,首节点的线程在释放锁时,会唤醒后续节点,而后继节点在成功获取到锁后,会把自己设置成首节点,设置首节点是由获取锁成功的线程来完成的,由于只有一个线程能成功获取到锁,所以设置首节点不需要CAS

AQS实现一个线程安全的计数器

自定义互斥锁

package com.rumenz.task.aqs;import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class MyLock {private static final Sync STATE_HOLDER = new Sync();/*** 通过Sync内部类来持有同步状态, 当状态为1表示锁被持有,0表示锁处于空闲状态*/private static class Sync extends AbstractQueuedSynchronizer {/*** 是否被独占, 有两种表示方式*  1. 可以根据状态,state=1表示锁被占用,0表示空闲*  2. 可以根据当前独占锁的线程来判断,即getExclusiveOwnerThread()!=null 表示被独占*/@Overrideprotected boolean isHeldExclusively() {return getExclusiveOwnerThread() != null;}/*** 尝试获取锁,将状态从0修改为1,操作成功则将当前线程设置为当前独占锁的线程*/@Overrideprotected boolean tryAcquire(int arg) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}/*** 释放锁,将状态修改为0*/@Overrideprotected boolean tryRelease(int arg) {if (getState() == 0) {throw new UnsupportedOperationException();}setExclusiveOwnerThread(null);setState(0);return true;}}/*** 下面的实现Lock接口需要重写的方法,基本是就是调用内部内Sync的方法*/public void lock() {STATE_HOLDER.acquire(1);}public void unlock() {STATE_HOLDER.release(1);}
}

测试案例

package com.rumenz.task.aqs;import org.omg.Messaging.SYNC_WITH_TRANSPORT;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;public class LockTest {private final static Integer clientTotal=100000;private final static Integer threadTotal=200;private static Count count=new Count();private static Count unSafe=new Count();public static void main(String[] args) throws Exception {ExecutorService executorService = Executors.newCachedThreadPool();final CountDownLatch countDownLatch=new CountDownLatch(clientTotal);final Semaphore semaphore=new Semaphore(threadTotal);for (int i = 0; i < clientTotal; i++) {executorService.execute(()->{try{semaphore.acquire();count.getIncrement();unSafe.getUnSafeIncrement();semaphore.release();}catch (Exception e){e.printStackTrace();}countDownLatch.countDown();});}countDownLatch.await();System.out.println("safe:"+count.getCount());System.out.println("unSafe:"+unSafe.getCount());executorService.shutdown();}}class Count{private MyLock myLock;private volatile int count;Count() {this.myLock=new MyLock();}int getCount(){return count;}int getIncrement(){myLock.lock();count++;myLock.unlock();return count;}int getUnSafeIncrement(){count++;return count;}
}

输出结果

safe:100000
unSafe:99995

关注微信公众号:【入门小站】,解锁更多知识点

AQS同步队列结构分析相关推荐

  1. AQS独占式同步队列入队与出队

    入队 Node AQS同步队列和等待队列共用同一种节点结构Node,与同步队列相关的属性如下. prev 前驱结点 next 后继节点 thread 入队的线程 入队节点的状态 INITIAl 0 初 ...

  2. AbstractQueuedSynchronizer同步队列与Condition等待队列协同机制

    之前对AbstractQueuedSynchronizer(AQS)同步队列与Condition等待队列的功能一直不是很清晰,没太清楚地区分开二者的区别和联系,最近研究了一下分享出来. 1.同步队列和 ...

  3. java8 同步队列_秋招之路8:JAVA锁体系和AQS抽象队列同步器

    整个的体系图 悲观锁,乐观锁 是一个广义概念:体现的是看待线程同步的不同角度. 悲观锁 认为在自己使用数据的时候一定有别的线程来修改数据,在获取数据的时候会先加锁,确保数据不被别的线程修改. 实现:关 ...

  4. 死磕Java并发:J.U.C之AQS:CLH同步队列

    本文转载自公号:Java技术驿站 在上篇文章"死磕Java并发:J.U.C之AQS简介"中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一个F ...

  5. Java Review - 并发编程_抽象同步队列AQS

    文章目录 概述 AQS--锁的底层支持 state 的作用 ConditionObject 独占 VS 共享 独占方式下,获取与释放资源的流程 共享方式下,获取与释放资源的流程 Interruptib ...

  6. 浅谈AQS(AbstractQueuedSynchronizer,同步队列)

    1.1 同步队列:队列中存放排队等待锁的线程,每个线程放入队列时会被包装为Node类,如下图.  1.2 抢锁:调用lock方法,如果抢锁成功(CAS成功,或者是重入--state计数加1),那么in ...

  7. java队列加锁_java并发-----浅析ReentrantLock加锁,解锁过程,公平锁非公平锁,AQS入门,CLH同步队列...

    前言 为什么需要去了解AQS,AQS,AbstractQueuedSynchronizer,即队列同步器.它是构建锁或者其他同步组件的基础框架(如ReentrantLock.ReentrantRead ...

  8. java同步队列_Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理

    前言 在 Java 中通过锁来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关 ...

  9. 【死磕Java并发】-----J.U.C之AQS:CLH同步队列

    原文出处:https://www.cmsblogs.com/category/1391296887813967872 『chenssy』 在上篇博客[死磕Java并发]-----J.U.C之AQS:A ...

最新文章

  1. Kubernetes源码分析之kubelet
  2. mysql查询职位大于3_4、MySQL查询(控制行)
  3. python windows控制台,如何从python启用Windows控制台快速编辑模式?
  4. html5 table的表头拖动,可拖动table表头的实现
  5. 决策类AI成最具商业价值应用产品 第四范式入选Gartner中国5大代表厂商
  6. 存储知识课堂(二):磁盘读写磁头揭秘
  7. 程序猿永远就是程序员的命么?
  8. Mo's Algorithm
  9. androidpn 推送初探
  10. MySQL显示连接的数据库名
  11. C 线程同步的四种方式(Windows)
  12. webstorm汉化流程
  13. 6个功能杰出的黑科技APP, 每一个都令你大开眼见!
  14. C语言面试常见问题总结
  15. 明白熊猫与冰墩墩的区别,就知道青云KubeSphere与QKCP该如何选择
  16. 高雅复古立式钢琴音源 Native Instruments The Gentleman Kontakt
  17. 软考高级系统架构设计师总结
  18. 【学习OpenCV4】聊聊图像格式
  19. android 自定义通知铃声设置在哪,安卓手机铃声自定义:短信通知、来电铃声怎么设置?...
  20. 用python代码实现 函数调用 烤红薯的例子

热门文章

  1. 移动一个网站集所使用的内容数据库
  2. Python 程序员必知必会的开发者工具
  3. java子字符串查找位置_初学者求教,如何在字符串中查找多个子字符串的位置...
  4. Mybatis 常见知识点问题
  5. [Java] 蓝桥杯ADV-170 算法提高 数字黑洞
  6. 【Sublime】Mac下Sublime代码自动换行
  7. python网络爬虫的特点_Python网络爬虫(一)- 入门基础
  8. hbase Java API 介绍及使用示例
  9. PHP,mysql,Linux,CI框架学习总结
  10. Android项目实战(二):安卓应用程序退出的三种方法