定义:
自旋锁(spin lock)是一种非阻塞锁,也就是说,如果某线程需要获取锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取锁。线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等待。
作用:
自旋锁避免了进程上下文的调度开销。线程一直处于用户态,减少了用户态到内核态的开销与损耗(减少了上下文切换)。
适用场景:
1、多线程
2、使用者占有锁的时间短。
Java自旋锁实现方式:
CAS
CAS是由操作系统定义的,由若干指令组成的,这个操作具有原子性,这些指令如果执行,就会全部执行完,不会被中断。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
Jdk1.5以后,提供了java.util.concurrent.atomic包,这个包里面提供了一组原子类。基本上就是当前获取锁的线程,执行更新的方法,其他线程自旋等待,比如atomicInteger类中的getAndAdd方法内部实际上使用的就是Unsafe的方法。
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
手写自旋锁
package thread.lock;
import java.util.concurrent.atomic.AtomicReference;
/**
* 自旋锁
*/
public class SpinLock {
//Creates a new AtomicReference with null initial value. value==null
private AtomicReference<Thread> cas = new AtomicReference<>();
public void lock() {
Thread currentThread = Thread.currentThread();
//自旋
while (!cas.compareAndSet(null, currentThread)) {
//如果期望值与内存值不一样(compareAndSet返回false)就一直循环
}
System.out.println(currentThread.getName() + " get lock,yeah");
}
public void unlock() {
Thread currentThread = Thread.currentThread();
cas.compareAndSet(currentThread, null);
System.out.println(currentThread.getName() + " release lock,yeah");
}
public static void main(String[] args) {
SpinLock spinLock = new SpinLock();
new Thread() {
@Override
public void run() {
try {
spinLock.lock();
for(int i=0;i<10;i++){
System.out.println(i);
}
} finally {
spinLock.unlock();
}
}
}.start();
new Thread() {
@Override
public void run() {
try {
spinLock.lock();
for(int i=100;i<110;i++){
System.out.println(i);
}
} finally {
spinLock.unlock();
}
}
}.start();
}
}
运行结果:
Thread-0 get lock,yeah
0
1
2
3
4
5
6
7
8
9
Thread-0 release lock,yeah
Thread-1 get lock,yeah
100
101
102
103
104
105
106
107
108
109
Thread-1 release lock,yeah
参考文章:自旋锁以及Java中的自旋锁的实现