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

 在谈到CHL Node FIFO队列之前,我们先分析这样的队列的几个要素。

首先要了解的是自旋锁。所谓自旋锁即是某一线程去尝试获取某个锁时。假设该锁已经被其它线程占用的话。此线程将不断循环检查该锁是否被释放,而不是让此线程挂起或睡眠。它属于为了保证共享资源而提出的一种锁机制,与相互排斥锁类似,保证了公共资源在随意时刻最多仅仅能由一条线程获取使用。不同的是相互排斥锁在获取锁失败后将进入睡眠或堵塞状态。以下利用代码实现一个简单的自旋锁,

public class SpinLock {

private static Unsafe unsafe = null;

private static final long valueOffset;

private volatile int value = 0;

static {

try {

unsafe=getUnsafeInstance();

valueOffset = unsafe.objectFieldOffset(SpinLock.class

.getDeclaredField("value"));

} catch (Exception ex) {

throw new Error(ex);

}

}

private static Unsafe getUnsafeInstance() throws SecurityException,

NoSuchFieldException, IllegalArgumentException,

IllegalAccessException {

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

theUnsafeInstance.setAccessible(true);

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

}

public void lock() {

for (;;) {

            int newV = value + 1;

            if (unsafe.compareAndSwapInt(this, valueOffset, 0, newV)){

            return ;

            }

        }

}

public void unlock() {

unsafe.compareAndSwapInt(this, valueOffset, 1, 0);

}

}

这是一个非常easy的自旋锁,主要看加粗加红的两个方法lock和unlock,Unsafe不过为操作提供了硬件级别的原子CAS操作,临时忽略此类,只要知道它的作用就可以,我们将在后面的“原子性怎样保证”小节中对此进行更加深入的阐述。

对于lock方法,假如有若干线程竞争,能成功通过CAS操作改动value值为newV的线程即是成功获取锁的线程。将直接通过,而其它的线程则不断在循环检測value值是否又改回0,而将value改为0的操作就是获取锁的线程运行完后对该锁进行释放,通过unlock方法释放锁,释放后若干线程又对该锁竞争。如此一来。没获取的锁也不会被挂起或堵塞,而是不断循环检查状态。图2-5-9-3可加深自旋锁的理解。五条线程轮询value变量,t1获取成功后将value置为1。此状态时其它线程无法竞争锁,t1使用完锁后将value置为0。剩下的线程继续竞争锁,以此类推。这样就保证了某个区域块的线程安全性。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3lhbmd6aGl6aG91/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast"> 

图2-5-9-3 自旋锁

自旋锁适用于锁占用时间短,即锁保护临界区非常小的情景,同一时候它须要硬件级别操作。也要保证各缓存数据的一致性,另外,无法保证公平性,不保证先到先获得。可能造成线程饥饿。

在多处理器机器上,每一个线程相应的处理器都对同一个变量进行读写,而每次读写操作都将要同步每一个处理器缓存。导致系统性能严重下降。

喜欢研究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阻塞队列管理(二)——自旋锁优化

    看Craig, Landin, and Hagersten发明的CLH锁如何优化同步带来的花销,其核心思想是:通过一定手段将所有线程对某一共享变量轮询竞争转化为一个线程队列且队列中的线程各自轮询自己的 ...

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

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

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

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

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

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

  7. Java并发框架——AQS之如何使用AQS构建同步器

    AQS的设计思想是通过继承的方式提供一个模板让大家可以很容易根据不同场景实现一个富有个性化的同步器.同步器的核心是要管理一个共享状态,通过对状态的控制即可以实现不同的锁机制.AQS的设计必须考虑把复杂 ...

  8. Java并发框架——AQS之怎样使用AQS构建同步器

    AQS的设计思想是通过继承的方式提供一个模板让大家能够非常easy依据不同场景实现一个富有个性化的同步器.同步器的核心是要管理一个共享状态,通过对状态的控制即能够实现不同的锁机制. AQS的设计必须考 ...

  9. Java并发框架——AQS超时机制

    AQS框架提供的另外一个优秀机制是锁获取超时的支持,当大量线程对某一锁竞争时可能导致某些线程在很长一段时间都获取不了锁,在某些场景下可能希望如果线程在一段时间内不能成功获取锁就取消对该锁的等待以提高性 ...

随机推荐

  1. 虚拟机克隆linux系统后需要做的网络设置

    1.vim /etc/sysconfig/network-scripts/ifcfg-eth0删除HWMAC地址行,然后重新分配静态IP/掩码/网关/DNS 2.vim /etc/udev/rules ...

  2. 什么是系统平均负载(Load average)

    一.什么是系统平均负载(Load average)? 在Linux系统中,uptime.w.top等命令都会有系统平均负载load average的输出,那么什么是系统平均负载呢? Load Aver ...

  3. iOS9适配+warning消除

    最近做了iOS 9的适配,程序出现大量警告也做了些处理,写出来分先给大家. 一.iOS 9适配 问题一: <Error>: CGContextSaveGState: invalid con ...

  4. CUICatalog: Invalid asset name supplied:

    [UIImage imageNamed:name];但是这个name却是空的,所以就报了这个错了. 解决方法,在项目中搜索UIImage imageNamed:,然后打印看看所谓的name是否为空.找 ...

  5. c#串口编程时,忽略跨线程检查报错

    1.直接在main_Form_Load的初始化中加 //忽略跨线程检查 // System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls ...

  6. Opensuse13.2开启ssh

    要开启ssh很简单,步骤分为三步 步骤1: 安装ssh zypper install ssh 步骤2:启动ssh daemon网上很多通过 service 命令或者 init.d 目录中的脚本启动ss ...

  7. ashx中session的使用

    在平常的页面上是用是很容易就的到request,response对像,从而对其进行一些操作,但在ashx(一般处理程序)中却是有一点的不同, 在ashx你无法正常的使用session,即 contex ...

  8. EF 执行顺序--先删除在更新和添加

    public void AcceptAllChanges() { if (this.ObjectStateManager.SomeEntryWithConceptualNullExists()) { ...

  9. DataTable 导出Excel 下载 (NPOI)

        public class ExcelHelper { public void DownLoadExcelNew(System.Data.DataTable data, Hashtable h, ...

  10. Python(四):数字连珠2

    对上次的代码作了一些修改.在码的过程中发现,最核心的部分是在横向.竖向和两个对角方向上找到5个以上相同的数字. 自己的思路是将x行y列所在的x行.y列,以及以此为交叉点的两点对角线上的数字,转化成字符 ...