自旋锁实现理解

文章目录

  • 自旋锁实现理解
      • 锁类型
      • 一种自旋锁的简单实现
      • TicketLock实现
      • CLHLock
      • MCSLock
      • CLH锁与MCS锁的比较
  • Reference

自旋锁实现理解

锁类型

  • 可重入锁:基于线程维度,递归锁定、再一层一层释放。

  • 可中断锁:等待锁期间可以被中断。

  • 公平锁:等待时间最长的锁优先被给到。

  • 读写锁:读写分离,一个读锁,一个写锁,提高并发。

  • 自旋锁:自旋是一种"原地忙等"策略,线程未获得锁则原地等待,不去睡眠,直到锁被释放,即不放弃CPU时间片,避免线程进入阻塞状态的开销(线程的阻塞挂起处理器需要切换上下文)。注意:自旋一般会设定一个过期时间,防止长时间自旋导致CPU时间片被长时间占用。自旋是等待他人,不能等待自己,若递归过程中原地打转嵌套等待自己,就会进入死锁。

    适合:耗时较少的逻辑中,对共享数据的保护,每个线程持有的自旋锁的时间较短。

    优点:等待的线程发现自旋锁被其他线程持有的时候,不必挂起自己,而是原地稍微等一会儿,直到锁被释放。所以,避免了线程切换带来的开销。

    缺点:等待自旋锁的线程一直占有CPU,如果长时间得不到自旋锁或者释放自旋锁,会导致CPU的浪费。另外,自旋锁可能导致死锁。

  • 互斥锁:线程未获得锁则去睡眠。

一种自旋锁的简单实现

  • SpinLock
package lockTest;

import java.util.concurrent.atomic.AtomicReference;

/**
 * 它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。
 * 但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
 */
public class SpinLock {
   
    /**
     * AtomicReference 原理:
     * unsafe获取偏移量 + 基址 定位到真实内存地址,cas操作保证原子性,volatile 修饰 value 保证可见性和有序性。
     * 类似版本号概念解 ABA 问题。
     * 自旋 失败重试 保障操作执行成功。
     *
     * holderWithSpinLock 为 持有自旋锁的线程对象。
     *
     * 无 static 保障每个操作的原子性,最终结果是100。(局部原子,并发)
     * 有 static 保障过程的串行化,从1加到100,每次获取锁、解开锁,最终得到100。(整体原子,串行)
     */
    private final AtomicReference<Thread> holderWithSpinLock = new AtomicReference<>();

//    private static final AtomicReference holderWithSpinLock = new AtomicReference<>();

    public AtomicReference<Thread> getHolderWithSpinLock() {
   
        return holderWithSpinLock;
    }

    /**
     * 不需要 volatile 修饰,因为不存在并发修改。是描述一个线程的自旋次数。
     * 可重入锁,计数重入次数。
     **/
    private int count = 0;

    public void lock(){
   
        // 当前线程
        Thread curThread = Thread.currentThread();
        System.out.println("curThread: "+ curThread + " start try enter lock with rotate.");
        // 如果是当前线程已经持有锁,则自旋次数加一。
        if(holderWithSpinLock.get() == curThread){
   
            System.out.println("curThread: "+ curThread + " is self rotate. count is: " + count);
            count++;
            return;
        }
        // 自旋 等待锁资源
        while(!holderWithSpinLock.compareAndSet(null, curThread)){
   
            System.out.println("curThread: "+ curThread + " is rotate.");
        }
        System.out.println("curThread: "+ curThread + " get lock success.")

你可能感兴趣的:(小小的天,天天JAVA,Java,锁,自旋锁实现)