logo头像
Snippet 博客主题

锁-未完成

本文于 942 天之前发表,文中内容可能已经过时。

操作系统级别如何实现锁

系统级别锁的实现

互斥锁

基本概念

互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。

自旋锁

基本概念

自旋锁是专为防止多处理器并发而引入的一种锁,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁。在多核环境下,操作系统通过锁内存总线这个机制保证锁的唯一性。

使用场景

只有在占用锁的时间极短的情况下,使用自旋锁才是合理的

注意事项

是递归使用一个自旋锁,即如果一个已经拥有某个自旋锁的CPU 想第二次获得这个自旋锁,则该CPU 将死锁。

java 级别如果实现锁

基本概念

调用操作系统

具体的实现

可重入锁

可重入锁的概念,持有锁的线程可以重复持有该锁。

自己实现的可重入锁

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
public class LocalReentrantLock  {

private AtomicReference<Thread> owner;
/**
* 被获取的次数
*/
private AtomicInteger counter;

private LinkedBlockingQueue<Thread> waitQueue;

public LocalReentrantLock() {
//阻塞队列
waitQueue = new LinkedBlockingQueue(100);
counter = new AtomicInteger(0);
owner=new AtomicReference<>();
}


/**
* 一直尝试获取锁
*/
public void lock() {
if (!tryLock()) {
//如果获取不到锁,放入到等待队列
waitQueue.offer(Thread.currentThread());
while (true) {
//取头部数据
Thread head = waitQueue.peek();
if (head == Thread.currentThread()) {
//如果头部等于当前线程
if (!tryLock()) {
//如果获取不到锁,说明是其它线程还占有的锁。挂起之后什么时候唤醒了,unlock的时候唤醒?
LockSupport.park();
} else {
//获取到了锁,直接弹出当前线程。
waitQueue.poll();
return;
}
} else {
LockSupport.park();
}
}
}
}


/**
* 尝试获取锁,获取不到锁,直接返回false
*
* @return
*/
public boolean tryLock() {
int count = counter.get();
if (count > 0) {
if (owner.get() == Thread.currentThread()) {
//拥有人是当前当前线程
counter.compareAndSet(count, count + 1);
return true;
} else {
//把当前线程放到等待队列里面
return false;
}
} else {
if (counter.compareAndSet(count, count + 1)) {
//如果当前线程能够设置成1,设置所有人为当前现线程。
owner.set(Thread.currentThread());
return true;
} else {
//被其它的线程抢占,设置了,直接返回false
return false;
}
}
}

/**
* 尝试解锁
*/
public boolean tryUnlock() {
int count = counter.get();
if (count > 0) {
if (owner.get() != Thread.currentThread()) {
throw new IllegalMonitorStateException("不能释放不是自己的锁");
}
// 这里面不做多线程的考虑,因为上面已经保证了操作下面方法的肯定是拥有人线程。
count = count - 1;
//设置引用次数减一
counter.set(count);
if (count == 0) {
owner.set(null);
return true;
}
return false;
} else {
throw new IllegalMonitorStateException("锁已经释放");
}
}

/**
* 解除锁定
*/
public void unlock() {
if(tryUnlock()){
//先释放当前锁的拥有人,如果可以释放,唤醒头部线程。
Thread head= waitQueue.peek();
if(head!=null){
/**
* 解锁头部线程
*/
LockSupport.unpark(head);
}
}
}
}
测试用例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) throws Exception {
LocalReentrantLock localReentrantLock = new LocalReentrantLock();
localReentrantLock.lock();
Thread.sleep(1000l);
System.out.println("主线程第一次获取锁");
new Thread(() -> {
localReentrantLock.lock();
System.out.println("t1 线程第一次获取锁");
localReentrantLock.unlock();
System.out.println("t1 线程解锁他获取的锁");
}).start();
localReentrantLock.lock();
Thread.sleep(1000l);
System.out.println("主线程第二次获取锁");
localReentrantLock.unlock();
System.out.println("主线程第一次释放锁");
localReentrantLock.unlock();
System.out.println("主线程第二次释放锁");
Thread.sleep(1000l);
}

读写锁

分布式锁

实现方式

基于redis的实现方式

reddsion

基于zookeeper的实现方式

curator