自旋锁spinlock
重点:尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,不会堵塞。缺点是循环会消耗 CPUpublic final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
手敲自旋锁:
代码:package com.juc.lock;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* Created by 逸轩 on 2021-01-20 17:27
*/
public class SpinLockDemo {
/**
* 原子引用线程
*/
AtomicReference atomicReference = new AtomicReference<>();
/**
* 自己写一个锁
*/
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + "\t come in !" + new Date());
// 交换不成功则一直自旋
while (!atomicReference.compareAndSet(null, thread)) {
}
}
/**
* 解锁
*/
public void myUnLock() {
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread, null);
System.out.println(thread.getName() + "\t go out !" + new Date());
}
public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(() -> {
spinLockDemo.myLock();
try {
// 线程1在6秒后才释放锁
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
spinLockDemo.myUnLock();
}, "Thread1").start();
// 等两秒才开始线程2
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
spinLockDemo.myLock();
spinLockDemo.myUnLock();
}, "Thread2").start();
}
}Thread1 come in !Tue May 05 20:02:54 CST 2020
Thread2 come in !Tue May 05 20:02:56 CST 2020
Thread1 go out !Tue May 05 20:03:00 CST 2020
Thread2 go out !Tue May 05 20:03:00 CST 2020
从结果可以看出,在线程 1 还没有释放锁时,线程 2 无法执行操作,仅仅是进入后不断循环直到线程 1 释放锁。
这就是自旋锁的妙处。