并发编程系列之CLH锁

简介: 并发锁之CLH锁

CLH加锁&解锁流程

CLH_

CLHLock作为自旋、公平并发锁,其实现思路较为简单。文中使用了ThreadLocal结构来维护每个线程的当前结点(CurrentNode)和前驱结点(PrevNode)信息。当前线程通过调用lock()方法,在前驱结点的voliate变量lock自旋,实现对共享资源的监听。

如图所示,在线程尝试取锁时,会在调用ThreadLocal.get()方法内部构造新的CLHNode,并将该CLHNode的lock字段置为true,表示当前线程"持有"锁;同时修改当前线程"指向"的前驱CLHNode结点为上一次取锁后的tail指针指向的CLHNode。如此便完成了取锁-自旋的过程。

实现

  • 申明ILock接口
/**
 * Created by fujianbo on 2018/3/24.
 *
 * @author fujianbo
 * @date 2018/03/24
 */
public interface ILock {
    /**
     * 线程获取锁惭怍
     * @param thread
     * @throws InterruptedException
     */
    void lock() throws InterruptedException;

    /**
     * 线程释放锁操作
     * @param thread
     */
    void unlock();
}
  • 定义CLHNode数据结构
/**
 * Created by fujianbo on 2018/3/24.
 *
 * @author fujianbo
 * @date 2018/03/24
 */
public class CLHNode {
    /** 当前结点是否被线程持有 */
    private volatile boolean isLock = false;
    /** 拥有当前结点的线程 */
    private Thread thread;

    public Thread getThread() {
        return thread;
    }

    public void setThread(Thread thread) {
        this.thread = thread;
    }

    public boolean isLock() {
        return isLock;
    }

    public void setLock(boolean lock) {
        isLock = lock;
    }
}
  • 【重要】CLH取锁&释放锁逻辑
/**
 * Created by fujianbo on 2018/3/24.
 *
 * CLH锁实现
 * @author fujianbo
 * @date 2018/03/24
 */
public class CLHLock implements ILock {
    private AtomicReference<CLHNode> tail = new AtomicReference<>(new CLHNode());
    private ThreadLocal<CLHNode> current = new ThreadLocal() {
        @Override
        protected Object initialValue() {
            return new CLHNode();
        }
    };

    private ThreadLocal<CLHNode> prev = new ThreadLocal();

    @Override
    public void lock() {
        // 初始化线程上下文
        CLHNode threadCurrentNode = current.get();
        threadCurrentNode.setLock(true);
        // 获取tail地址并将tail指向新生成的CLHNode
        CLHNode threadPrevNode = tail.getAndSet(threadCurrentNode);
        this.prev.set(threadPrevNode);
        // 自旋等待
        while (this.prev.get().isLock()) {
            System.out.println("thread:" + Thread.currentThread().getName() + "is trying to get lock...!");
        }

        System.out.println("thread:" + Thread.currentThread().getName() + "succeed to get lock!");
    }

    @Override
    public void unlock() {
        CLHNode threadCurrentNode = current.get();
        current.set(null);
        prev.set(null);
        threadCurrentNode.setLock(false);
    }
  • 测试用例
/**
 * Created by fujianbo on 2018/3/25.
 *
 * @author fujianbo
 * @date 2018/03/25
 */
public class CLHLockTest {
    private static final int THREAD_NUM = 10;
    private static int total = 0;

    public static void main(String[] args) {
        CLHLock clhLock = new CLHLock();
        for (int idx=0 ; idx<THREAD_NUM ; ++idx) {
            new Thread() {
                @Override
                public void run() {
                    clhLock.lock();
                    CLHLockTest.total++;
                    clhLock.unlock();
                }
            }.start();
        }
    }
}

错误分析

  • 手误导致未初始化tail节点导致线程死锁
private AtomicReference<CLHNode> tail = new AtomicReference<>(new CLHNode()); //before: private AtomicReference<CLHNode> tail = new AtomicReference<>();
目录
相关文章
|
监控 druid
druid 连接池监控报错 Sorry, you are not permitted to view this page.
druid 连接池监控报错 Sorry, you are not permitted to view this page.
1179 0
|
5月前
|
存储 关系型数据库 MySQL
阿里云数据库产品支持免费试用吗?最新可试用数据库规格信息、配置及可试用人群参考
2026年阿里云数据库试用活动的核心内容参考,涵盖26款可试用数据库产品,包括RDS MySQL、Tair、PolarDB、AnalyticDB等主流类型,覆盖Serverless、集群版、多模态等多种形态。活动支持个人与企业认证用户,适用场景涵盖开发测试、生产环境、AI集成、实时分析等。新用户可享免费试用额度及后续折扣。
1557 6
|
5月前
|
机器学习/深度学习 数据安全/隐私保护 iOS开发
Mac安装Miniconda完整指南(从零开始配置Python环境)
本教程详细介绍如何在Mac上从零安装Miniconda,配置Python环境。涵盖下载、安装、验证及常用Conda命令,帮助用户轻松搭建数据科学开发环境,适合新手快速上手。
|
监控 druid
druid 连接池监控报错 Sorry, you are not permitted to view this page.
druid 连接池监控报错 Sorry, you are not permitted to view this page.
2820 0
Java 线程同步的四种方式,最全详解,建议收藏!
本文详细解析了Java线程同步的四种方式:synchronized关键字、ReentrantLock、原子变量和ThreadLocal,通过实例代码和对比分析,帮助你深入理解线程同步机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 线程同步的四种方式,最全详解,建议收藏!
|
Java Android开发 数据安全/隐私保护
Android中多进程通信有几种方式?需要注意哪些问题?
本文介绍了Android中的多进程通信(IPC),探讨了IPC的重要性及其实现方式,如Intent、Binder、AIDL等,并通过一个使用Binder机制的示例详细说明了其实现过程。
1191 4
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)
|
JSON Java 测试技术
jsonpath :从入门到精通
jsonpath :从入门到精通
|
人工智能 缓存 算法
【AI 孙燕姿 | AI 音色克隆】RVC 使用图文教程:无难度男女换声(伪音)、 AI 孙燕姿
根据本文,可以很简单实现:音乐干声分离:背景音(BGM)与人声(干声)的分离;训练个人音色模型:作为模仿其他干声素材的音色数据;男女换声(伪音):基于异性干声素材,进行实时转化声音为异性声音;AI 唱歌:仅作基础的模拟演唱,仍需进行调音等等操作,才可以达到完美;音色融合:不同音色的特征融合出一个全新的音色
8901 3
【AI 孙燕姿 | AI 音色克隆】RVC 使用图文教程:无难度男女换声(伪音)、 AI 孙燕姿

热门文章

最新文章