Home Java Lock
Post
Cancel

Java Lock

Lock 和 Synchronized 的区别

  1. 灵活性: 通过 Locck, 可以更细粒度地控制锁的获得和释放,可以在不同的方法调用 lock()unlock() 方法。但是,Synchronized 必须完全包含在单个方法内部。
  2. 公平性: Lock 允许你在获取锁的过程中选择公平性或者非公平性。公平性确保锁按照请求的顺序授予等待的线程,而非公平性可能允许某些线程在其他线程之前获得锁。相比之下, Synchronized 遵循非公平的锁定机制。
  3. 超时: 使用 Lock, 你可以在获取锁时指定超市时间,通过 tryLock() 方法实现,这允许你尝试在指定的时间内获得锁,并在超时时采取适当的操作。而在 Synchronized 中没有内在的机制设置超时时间。
  4. 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) {
            // 处理中断异常
            // ...
        }
    }
}

This post is licensed under CC BY 4.0 by the author.
Contents