什么是自旋锁?
解释:自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时才能进入临界区。
简单描述:用循环的方式去获取一个锁的资格
之前的博客也提到如下:
sun.misc.Unsafe是jdk/jre/lib目录下的rt.jar中的类,也就可以理解成Java自带的吧
那将这个jar包反编译可以看到具体的getAndAddInt方法实现如下:
1
2
3
4
5
6
7
public final int getAndAddInt(Object paramObject, long paramLong, int paramInt) {
int i;
do {
i = getIntVolatile(paramObject, paramLong);
} while (!compareAndSwapInt(paramObject, paramLong, i, i + paramInt));
return i;
}
这个do-while的形式就有自旋的实现,如果compareAndSwapInt失败就再次循环getIntVolatile后再次compareAndSwapInt…
Demo实现
上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* JDK 1.8 手写自旋锁Demo
*
* 简单描述:用循环的方式去获取一个锁的资格
*
* 注:该例子为非公平锁,获得锁的先后顺序,不会按照进入myLock的先后顺序进行。
*
* 这句话的意思是说,下面的t1/t2/t3/t4会第一时间有序调用myLock,但是并不保证按顺序获取到锁
*
* 下面执行的情况为例:
*
* t1,调用myLock()
t2,调用myLock()
t3,调用myLock()
t4,调用myLock()
t2,正在等待其他线程释放锁
t3,正在等待其他线程释放锁
t4,正在等待其他线程释放锁
t4,正在等待其他线程释放锁
t3,正在等待其他线程释放锁
t2,正在等待其他线程释放锁
t2,正在等待其他线程释放锁
t4,正在等待其他线程释放锁
t3,正在等待其他线程释放锁
t2,正在等待其他线程释放锁
t4,正在等待其他线程释放锁
t3,正在等待其他线程释放锁
t2,正在等待其他线程释放锁
t1,调用myUnLock(),释放锁
t4,正在等待其他线程释放锁
t3,正在等待其他线程释放锁
t3,正在等待其他线程释放锁
t4,正在等待其他线程释放锁
t2,调用myUnLock(),释放锁
t3,正在等待其他线程释放锁
t4,调用myUnLock(),释放锁
t3,调用myUnLock(),释放锁
*
* @author nobt
*
*/
public class SpinLockDemo {
// 借助原子引用类
AtomicReference<Thread> atomicReference = new AtomicReference<>();
//加锁
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+",调用myLock()");
/**
* atomicReference.compareAndSet(null, thread)
* 它的意思是如果atomicReference对象中的值是null,那么就把atomicReference的值改为当前调用的线程引用(对象)
* 如果更新/修改成功,那么返回true,否则返回false
*
* 所以如果修改失败、返回false,将会一直while循环(此时就是等待其他线程释放锁的场景)
*/
while(!atomicReference.compareAndSet(null, thread)){
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(thread.getName()+",正在等待其他线程释放锁");
}
}
//解锁
public void myUnLock() {
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread, null);
System.out.println(thread.getName()+",调用myUnLock(),释放锁");
}
public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
//线程1
new Thread(() -> {
spinLockDemo.myLock();
//线程t1调用myLock后就持有锁了,sleep(5)相当于持有锁5秒,在持有状态下,其它线程会一直在myLock方法的while循环中
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
spinLockDemo.myUnLock();
},"t1").start();
//线程2
new Thread(() -> {
spinLockDemo.myLock();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
spinLockDemo.myUnLock();
},"t2").start();
//线程3
new Thread(() -> {
spinLockDemo.myLock();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
spinLockDemo.myUnLock();
},"t3").start();
//线程4
new Thread(() -> {
spinLockDemo.myLock();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
spinLockDemo.myUnLock();
},"t4").start();
}
}