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


    我们知道一个线程在尝试获取锁失败后将被堵塞并增加等待队列中,它是一个如何的队列?又是如何管理此队列?这节聊聊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。剩下的线程继续竞争锁,以此类推。这样就保证了某个区域块的线程安全性。


     
    图2-5-9-3 自旋锁

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

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


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




  • 相关阅读:
    采用get方式提交数据到服务器实例
    android之HttpURLConnection
    Android中的传感器
    有符号类型无符号类型转换
    一些常用位运算示例
    C++ / CLI 调用 C++ /Native 随记
    Linux Shell Demo
    Linux Shell 脚本入门
    Linux 编译 websocket++
    Linux 编写c++程序之openssl
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5240806.html
Copyright © 2020-2023  润新知