看Craig, Landin, and Hagersten发明的CLH锁如何优化同步带来的花销,其核心思想是:通过一定手段将所有线程对某一共享变量轮询竞争转化为一个线程队列且队列中的线程各自轮询自己的本地变量。这个转化过程由两个要点,一是构建怎样的队列&如何构建队列,为了保证公平性,构建的将是一个FIFO队列,构建的时候主要通过移动尾部节点tail实现队列的排队,每个想获取锁的线程创建一个新节点并通过CAS原子操作将新节点赋予tail,然后让当前线程轮询前一节点的某个状态位,如图2-5-9-3,如此就成功构建线程排队队列;二是如何释放队列,执行完线程后只需将当前线程对应的节点状态位置为解锁状态,由于下一节点一直在轮询,可获取到锁。

 

图2-5-9-3 CLH锁

CLH锁的核心思想貌似是将众多线程长时间对某资源的竞争,通过有序化这些线程转化为只需对本地变量检测。唯一存在竞争的地方就是在入队列之前对尾节点tail的竞争,但竞争的线程的数量已经少了很多,且比起所有线程直接对某资源竞争的轮询次数也减少了很多,节省了很多CPU缓存同步操作,大大提升系统性能,利用空间换取性能。下面提供一个简单的CLH锁实现代码,lock与unlock两方法提供加锁解锁操作,每次加锁解锁必须将一个CLHNode对象作为参数传入,lock方法的for循环是通过CAS操作将新节点插入队列,而while循环则是检测前驱节点的锁状态位,一旦前驱节点锁状态位允许则结束检测让线程往下执行。解锁操作先判断当前节点是否为尾节点,如是则直接将尾节点置为空,此时说名仅仅只有一条线程在执行,否则将当前节点的锁状态位置为解锁状态。





public class CLHLock {





private static Unsafe unsafe = null;

private static final long valueOffset;

private volatile CLHNode tail;

public class CLHNode {

private boolean isLocked = true;

}





static {

try {

unsafe = getUnsafeInstance();

valueOffset = unsafe.objectFieldOffset(CLHLock.class

.getDeclaredField("tail"));

} catch (Exception ex) {

throw new Error(ex);

}

}





public void lock(CLHNode currentThreadNode) {

CLHNode preNode = null;

for (;;) {

preNode = tail;

if (unsafe.compareAndSwapObject(this, valueOffset, tail,

currentThreadNode))

break;

}

if (preNode != null)

while (preNode.isLocked) {

}

}





public void unlock(CLHNode currentThreadNode) {

  if (!unsafe.compareAndSwapObject(this, valueOffset, currentThreadNode,null))

   currentThreadNode.isLocked = false;

}





private static Unsafe getUnsafeInstance() throws SecurityException,

NoSuchFieldException, IllegalArgumentException,

IllegalAccessException {

Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");

theUnsafeInstance.setAccessible(true);

return (Unsafe) theUnsafeInstance.get(Unsafe.class);

}

}

喜欢研究java的同学可以交个朋友,下面是本人的微信号:

Java并发框架——AQS阻塞队列管理(二)——自旋锁优化的更多相关文章

  1. Java并发框架——AQS阻塞队列管理(三)——CLH锁改造

    在CLH锁核心思想的影响下,Java并发包的基础框架AQS以CLH锁作为基础而设计,其中主要是考虑到CLH锁更容易实现取消与超时功能.比起原来的CLH锁已经做了很大的改造,主要从两方面进行了改造:节点 ...

  2. Java并发框架——AQS阻塞队列管理(一)——自旋锁

    我们知道一个线程在尝试获取锁失败后将被阻塞并加入等待队列中,它是一个怎样的队列?又是如何管理此队列?这节聊聊CHL Node FIFO队列. 在谈到CHL Node FIFO队列之前,我们先分析这种队 ...

  3. Java并发框架——AQS堵塞队列管理(一)——自旋锁

    我们知道一个线程在尝试获取锁失败后将被堵塞并增加等待队列中,它是一个如何的队列?又是如何管理此队列?这节聊聊CHL Node FIFO队列.  在谈到CHL Node FIFO队列之前,我们先分析这样 ...

  4. 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.AQS框架简介 AQS诞生于Jdk1.5,在当时低效且功能单一的synchroni ...

  5. 深入理解Java并发框架AQS系列(一):线程

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...

  6. 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...

  7. Java并发编程:阻塞队列(转载)

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  8. 【转】Java并发编程:阻塞队列

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  9. 12、Java并发编程:阻塞队列

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

随机推荐

  1. bzoj2149拆迁队 斜率优化dp+分治

    2149: 拆迁队 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 397  Solved: 177[Submit][Status][Discuss] ...

  2. gray-code (格雷码)

    题目描述 The gray code(格雷码) is a binary numeral system where two successive values differ in only one bi ...

  3. super 关键字

  4. AQS简简单单过一遍

    前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 Java锁机制了解一下 只有光头才能变强! 本来我是打算在这章节中写Lock的子类实 ...

  5. 读书笔记-《Maven实战》-关于Maven依赖传递的思考 2018/4/26

    上次读书笔记中,提到了依赖传递.看着依赖传递表,一直在思考为什么会是这样. 先看传递表: compile test provided runtime compile test provided run ...

  6. 判断是否是IE9浏览器的最短语句 var ie=!-[1,]

    没错,上面这个语句就可以判断浏览器是不是IE9以下的.why?1.[1,]在现代浏览器(ie包括ie9及以上)会被转换成[1], 而ie9以下就会转换成[1,undefined].2.分别对[1],和 ...

  7. mysql常见的优化需要注意的点

    1.explain分析explian引用索引基数show indexes from table_name;主键索引具有最好的基数 测试时 不走缓存SELECT SQL_NO_CACHE id from ...

  8. CentOS6.8虚拟机安装及ORALCE安装记录

    CENTOS6.8安装数据库及设置自启动脚本教程 作者:张欣橙 本文所需要的所有参数均位于文末附录中 一.新建虚拟机 选择下一步 选择下一步 选择稍后安装操作系统 选择LINUX 版本 CentOS ...

  9. Python学习---字符串处理

    This world is but a canvas to our imagination. 世界只是我们的想象的画布. ----Apri 22 ''' 题目内容: "Pig Latin&q ...

  10. OO第一阶段总结

    OO第一阶段总结 一.各次作业程序结构 第一次作业 第一次作业由于初用JAVA,还没有深刻理解面向对象的编程方法,故在编程过程中只用了一个类,一个方法,即完成了相应的程序功能.这必然不是本课程的目的, ...