Lock 和 Synchronized 的区别
- 灵活性: 通过 Locck, 可以更细粒度地控制锁的获得和释放,可以在不同的方法调用
lock()和unlock()方法。但是,Synchronized 必须完全包含在单个方法内部。 - 公平性: Lock 允许你在获取锁的过程中选择公平性或者非公平性。公平性确保锁按照请求的顺序授予等待的线程,而非公平性可能允许某些线程在其他线程之前获得锁。相比之下, Synchronized 遵循非公平的锁定机制。
- 超时: 使用 Lock, 你可以在获取锁时指定超市时间,通过
tryLock()方法实现,这允许你尝试在指定的时间内获得锁,并在超时时采取适当的操作。而在 Synchronized 中没有内在的机制设置超时时间。 - Lock提供了一些额外的功能,在某些情况下非常有用。例如,ReentrantLock在初始化时允许你指定公平或非公平锁。此外,Lock还支持条件变量,允许线程在满足特定条件之前等待。
可重入锁
ReentrantLock 类是可重入锁。这意味着,即使线程持有该保留,它也可以再次锁定它。因此,线程必须解锁它的次数与锁定它的次数相同,以便完全解锁其他线程的可重入锁。
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
public class Calculator {
public static class Calculation {
public static final int UNSPECIFIED = -1;
public static final int ADDITION = 0;
public static final int SUBTRACTION = 1;
int type = UNSPECIFIED;
public double value;
public Calculation(int type, double value){
this.type = type;
this.value = value;
}
}
private double result = 0.0D;
Lock lock = new ReentrantLock();
public void add(double value) {
try {
lock.lock();
this.result += value;
} finally {
lock.unlock();
}
}
public void subtract(double value) {
try {
lock.lock();
this.result -= value;
} finally {
lock.unlock();
}
}
public void calculate(Calculation ... calculations) {
try {
lock.lock();
for(Calculation calculation : calculations) {
switch(calculation.type) {
case Calculation.ADDITION : add (calculation.value); break;
case Calculation.SUBTRACTION: subtract(calculation.value); break;
}
}
} finally {
lock.unlock();
}
}
}
锁的公平性
ReentrantLock类提供了tryLock()方法来尝试获取锁。然而,需要注意的是,不带参数的tryLock()方法不会遵守ReentrantLock的公平性模式。公平性模式指的是锁按照线程请求的顺序进行分配。
确保锁的公平性,你应该使用带有超时参数的tryLock(long timeout, TimeUnit unit)方法。通过指定超时时间,该方法将在指定的时间内尝试获取锁,如果在超时之前锁可用,则获取锁成功;如果超过超时时间仍然无法获取锁,则获取锁失败。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class FairnessExample {
private ReentrantLock lock = new ReentrantLock(true); // 使用公平性模式
public void doSomething() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) { // 等待5秒钟尝试获取锁
try {
// 执行需要锁保护的操作
// ...
} finally {
lock.unlock(); // 释放锁
}
} else {
// 无法在规定时间内获取锁,做相应的处理
// ...
}
} catch (InterruptedException e) {
// 处理中断异常
// ...
}
}
}