自旋锁的介绍,手写一个简单的自旋锁

3,255 阅读1分钟

一、简介

自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区,线程尝试获取锁的过程不会阻塞;

二、分析

1、使用好处

  1. 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快
  2. 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。 (线程被阻塞后便进入内核(Linux)调度状态,这个会导致系统在用户态与内核态之间来回切换,严重影响锁的性能)

2、带来的问题

    1. 如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗            CPU。使用不当会造成CPU使用率极高。

   2. 可能会带来“线程饥饿”的情况;

三、手写一个JAVA自旋锁便于理解

package com.xxx.lcloud.study;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Created by gift on 2020-5-19.
 */
public class SpinLock {
   AtomicReference<Thread> atomicReference = new AtomicReference<>();

   public static void main(String[] args) {
      SpinLock spinLock = new SpinLock();
      new Thread(()->{
         spinLock.lock();
         try {
            TimeUnit.SECONDS.sleep(2);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         spinLock.unLock();
      },"线程A").start();

      try {
         TimeUnit.SECONDS.sleep(1);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }

      new Thread(()->{
         spinLock.lock();
         try {
            TimeUnit.SECONDS.sleep(1);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         spinLock.unLock();

      },"线程B").start();
   }

   private void lock(){
      Thread thread = Thread.currentThread();
      //准备抢占
      while(!atomicReference.compareAndSet(null,thread)){
            //空轮询
      }
   }

   private void unLock(){
      Thread thread = Thread.currentThread();
      atomicReference.compareAndSet(thread,null);
   }
}