并发编程系列之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<>();
目录
相关文章
|
6月前
|
Java
Java并发编程中的锁机制
【2月更文挑战第22天】 在Java并发编程中,锁机制是一种重要的同步手段,用于保证多个线程在访问共享资源时的安全性。本文将介绍Java锁机制的基本概念、种类以及使用方法,帮助读者深入理解并发编程中的锁机制。
|
6月前
|
安全 Java 测试技术
Java并发编程:理解线程同步和锁
【5月更文挑战第25天】本文深入探讨了Java并发编程的核心概念,即线程同步和锁。通过详细解释这两种机制,我们能够理解它们如何帮助解决多线程环境中的竞态条件问题。此外,文章还提供了一些示例代码,以展示如何在Java中使用这些技术。
|
2月前
|
Java 数据库
JAVA并发编程-一文看懂全部锁机制
曾几何时,面试官问:java都有哪些锁?小白,一脸无辜:用过的有synchronized,其他不清楚。面试官:回去等通知! 今天我们庖丁解牛说说,各种锁有什么区别、什么场景可以用,通俗直白的分析,让小白再也不怕面试官八股文拷打。
|
6月前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。
51 4
|
缓存 算法 安全
06.一文看懂并发编程中的锁
大家好,我是王有志。相信你经常会听到读锁/写锁,公平锁/非公平锁,乐观锁/悲观锁等五花八门的锁,那么每种锁有什么用呢?它们又有什么区别呢?今天我们就一起聊聊并发编程中的各种锁。
192 1
06.一文看懂并发编程中的锁
|
安全 编译器 C++
C++并发编程中的锁的介绍(二)
C++并发编程中的锁的介绍(二)
161 0
|
算法 安全 C++
C++并发编程中的锁的介绍(一)
C++并发编程中的锁的介绍(一)
192 0
|
Java API
【并发编程】锁机制
【并发编程】锁机制
java多线程和锁
多线程实现 方法1: 继承Thread类 public class Main { public static void main(String[] args) throws InterruptedException { Worker worker1 = new Worker(); worker1.setName("thread-worker1"); Worker worker2 = new Worker(); worker2.setName("thread_worker2"); worker1.start