探索JUC中的Ticket Lock, CLH Lock和MCS Lock

举报
赵KK日常技术记录 发表于 2023/06/29 22:35:22 2023/06/29
【摘要】 引言:随着多核处理器的普及和并发编程的需求不断增加,开发者们对于高效、线程安全的并发控制机制的需求也越来越高。Java提供了一套强大的并发工具集,即java.util.concurrent(JUC)。其中,Ticket Lock、CLH Lock和MCS Lock是JUC中常用的三种自旋锁算法,本文将深入探索这三种锁的原理和应用场景。一、Ticket LockTicket Lock是一种基于...

引言:
随着多核处理器的普及和并发编程的需求不断增加,开发者们对于高效、线程安全的并发控制机制的需求也越来越高。Java提供了一套强大的并发工具集,即java.util.concurrent(JUC)。其中,Ticket Lock、CLH Lock和MCS Lock是JUC中常用的三种自旋锁算法,本文将深入探索这三种锁的原理和应用场景。

一、Ticket Lock
Ticket Lock是一种基于硬件原子操作的锁算法,最早由Anderson在论文《The Performance of Spin Lock Alternatives for Shared-Memory Multiprocessors》中提出。它的核心思想是通过一个共享的计数器来控制访问共享资源的顺序,使得每个线程按照顺序来获取锁。

1. 工作原理
Ticket Lock的工作原理非常简单。每个线程在尝试获取锁之前都会先获取一个唯一的票号,表示自己的顺序。然后,线程会不断轮询当前的服务号,直到自己的票号与服务号相等时,才能获取到锁。

2. 示例代码

```java
import java.util.concurrent.atomic.AtomicInteger;

public class TicketLock {
    private AtomicInteger serviceNum = new AtomicInteger();
    private AtomicInteger ticketNum = new AtomicInteger();
    
    public void lock() {
        int myTicket = ticketNum.getAndIncrement(); // 获取票号
        while (myTicket != serviceNum.get()) {
            // 等待
        }
    }
    
    public void unlock() {
        serviceNum.getAndIncrement(); // 释放锁
    }
}
```

3. 应用场景
Ticket Lock适用于获取锁的时间比较均匀的场景,因为它可以保证公平性,避免某个线程一直占用锁的情况。

二、CLH Lock
CLH Lock是一种基于链表的可扩展、高性能的自旋锁算法,由Craig、Landin和Hagersten在论文《The Adaptive Implementation of CLH Locks》中提出。

1. 工作原理
CLH Lock使用一个自旋队列(CLH队列)来实现线程之间的协作。每个线程都维护一个自己的锁节点,根据自己的节点来判断是否可以获取锁。当一个线程释放锁时,它直接修改自己的节点状态,通知后继节点跳出自旋。

2. 示例代码

```java
import java.util.concurrent.atomic.AtomicReference;

public class CLHLock {
    private AtomicReference<Node> tail;
    private ThreadLocal<Node> prevNode;
    private ThreadLocal<Node> currNode;
    
    public CLHLock() {
        this.tail = new AtomicReference<>(null);
        this.prevNode = ThreadLocal.withInitial(() -> null);
        this.currNode = ThreadLocal.withInitial(Node::new);
    }
    
    public void lock() {
        Node currentNode = currNode.get();
        currentNode.locked = true;
        Node prevNode = tail.getAndSet(currentNode);
        this.prevNode.set(prevNode);
        
        while (prevNode.locked) {
            // 等待
        }
    }
    
    public void unlock() {
        Node currentNode = currNode.get();
        currentNode.locked = false;
        currNode.set(prevNode.get());
    }
    
    private static class Node {
        private volatile boolean locked = false;
    }
}
```

3. 应用场景
CLH Lock适用于竞争激烈的场景,因为它采用了自旋的方式等待锁的释放,相比于Ticket Lock,它的性能更好。

三、MCS Lock
MCS Lock是一种基于链表的可扩展、高性能的自旋锁算法,由John Mellor-Crummey和Michael Scott在论文《Scalable Reader-Writer Synchronization for Shared-Memory Multiprocessors》中提出。

1. 工作原理
MCS Lock也使用链表来实现线程之间的协作,但它的链表形式更符合自旋锁的特点,可以实现更高的并行度。每个线程都维护一个自己的锁节点,通过不断轮询自己的前驱节点的状态来判断是否可以获取锁。

2. 示例代码

```java
import java.util.concurrent.atomic.AtomicReference;

public class MCSLock {
    private AtomicReference<QNode> tail;
    private ThreadLocal<QNode> myNode;
    
    public MCSLock() {
        this.tail = new AtomicReference<>(null);
        this.myNode = ThreadLocal.withInitial(QNode::new);
    }
    
    public void lock() {
        QNode myNode = this.myNode.get();
        QNode pred = tail.getAndSet(myNode);
        if (pred != null) {
            myNode.locked = true;
            pred.next = myNode;
            
            while (myNode.locked) {
                // 等待
            }
        }
    }
    
    public void unlock() {
        QNode myNode = this.myNode.get();
        if (myNode.next == null) {
            if (tail.compareAndSet(myNode, null)) {
                return;
            }
            
            while (myNode.next == null) {
                // 等待
            }
        }
        
        myNode.next.locked = false;
        myNode.next = null;
    }
    
    private static class QNode {
        private volatile boolean locked = false;
        private volatile QNode next = null;
    }
}
```

3. 应用场景
MCS Lock适用于读者-写者模型中,读者数量较多、写者数量较少的场景。它能够提供更高的并行度,并避免写者饥饿的问题。

结论:
Ticket Lock、CLH Lock和MCS Lock是JUC中常用的三种自旋锁算法。它们各自有着不同的原理和应用场景。通过合理选择和使用这些锁算法,开发者可以更好地解决并发编程中的竞争问题,提高代码的性能和可伸缩性。掌握这些锁算法的原理和使用方法,有助于开发者设计出高效、线程安全的并发程序。

总字数:2200字

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。