概述

lock是java并发包提供的管程的一种实现,相较于jdk给出的synchronized,其具备以下优点:

  • 能够响应中断:synchronized的wait方法是可以响应中断的,不过在获取锁的时候(也就是还没有进入synchronized的方法体的时候)线程是没有办法响应中断的,而lock在入口等待队列以及条件等待队列中都是可以响应中断的,究其原因是lock在入口等待队列以及条件等待队列都是运行态(不包含runnable的状态)
  • 支持超时:synchronized是不支持超时的,这里的超时是获取锁的时候超时参数,并不是进入waiting、block中的超时,也即是获取锁的入口等待队列中是支持超时的
  • 非阻塞的获取锁:lock提供了fast fail的机制,在获取不到锁的时候可以快速失败,而不是一只阻塞

综上并发包中的lock保证了在获取锁的时候可中断、可超时、可快速失败。

示例

接下来通过代码演示一个使用lock实现的阻塞队列:

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
package com.hw;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestQueue {

private Object[] queue;

private Lock lock = new ReentrantLock();

Condition notFull = lock.newCondition();

Condition notEmpty = lock.newCondition();

private int start;

private int end;

private int size;

public TestQueue(int i) {
queue = new Object[i];
}

private void addElement(Object x) {

lock.lock();
while (size + 1 > queue.length) {
try {
notFull.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue[end % queue.length] = x;
end++;
size++;
notEmpty.signal();
lock.unlock();
}

private Object takeElement() throws InterruptedException {
lock.lock();
Object x = null;
while (size - 1 < 0) {
notEmpty.wait();
}
size--;
x = queue[start];
start = start++ % queue.length;
lock.unlock();
return x;
}
}

示例代码如上,这里不再详细描述了,其本质就是管程的一种实现,上面使用的锁的实现是可重入锁,其可以保障同一个线程可以对同一个锁多次加锁,并且这种锁提供了公平和非公平的机制,所谓的公平锁是在条件变量的队列上等待时间长的线程将会优先获得锁,而非公平锁则无法保障这种机制。

小结

本节先对java并发保重锁的实现进行分析,后面有时间的话会继续对其实现原理进行剖析