一、简介
自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区,线程尝试获取锁的过程不会阻塞;
二、分析
1、使用好处
- 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快
- 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。 (线程被阻塞后便进入内核(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);
}
}