显式锁ReentranLock的可中断锁获取操作

显式锁

显式锁,即Java接口Lock,ReentranLock是其中的一个实现,与synchronized一样具有可重入的特性,同时具有可以自定义公平性,可轮询,可定时,可中断的高级特性。是Java 5.0之后引入用于调节共享对象访问的机制。Java 6.0之后,synchronized做了很多优化,其性能和显示锁差异不大,因此在使用时,只有用到显示锁的高级特性才使用显示锁,特别是因为显示锁需要手动释放,所以具有一定的隐患。下面对显示锁可响应中断的高级特性进行测试。

不可中断的阻塞

在Java中,不可中断的阻塞可分为以下几类

  • java.io包中的同步Socket I/O
  • java.io包中的同步I/O
  • Selector的异步I/O
  • 获取某个锁

获取锁就是不可中断的阻塞,但是通过ReentranLock的lockInterruptibly()方法获取锁,是可以中断的,下面通过代码测试一下。思路即构造两个线程,通过请求互斥的条件达到死锁状态,获取锁时分别使用lock()和lockInterruptibly(),最后发现使用lock()来获取锁,阻塞时无法中断,而使用lockInterruptibly()获取锁,阻塞是可以中断的。

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

static Lock lock1 = new ReentrantLock();

static Lock lock2 = new ReentrantLock();

public static void main(String[] args)

throws InterruptedException {

Thread thread = new Thread(new ThreadDemo(lock1, lock2));

Thread thread1 = new Thread(new ThreadDemo1(lock2, lock1));

thread.start();

thread1.start();

thread.interrupt();//是第一个线程中断

}

static class ThreadDemo implements Runnable {
Lock firstLock;
Lock secondLock;
public ThreadDemo(Lock firstLock, Lock secondLock) {
this.firstLock = firstLock;
this.secondLock = secondLock;
}
@Override
public void run() {
try {
//firstLock.lock();
firstLock.lockInterruptibly();
for(int i = 0;i < 100000000;){
i++;
}//这里不使用sleep,因为sleep的阻塞是可中断的,那么即便用lock获取锁也会中断
secondLock.lockInterruptibly();
//secondLock.lock();;
} catch (Exception e) {
if(e instanceof InterruptedException) System.out.println(Thread.currentThread().getName() + "响应了中断");
else e.printStackTrace();
} finally {
firstLock.unlock();
secondLock.unlock();
System.out.println(Thread.currentThread().getName()
+"获取到了资源,正常结束!");
}
}
}

static class ThreadDemo1 implements Runnable {
Lock firstLock;
Lock secondLock;
public ThreadDemo1(Lock firstLock, Lock secondLock) {
this.firstLock = firstLock;
this.secondLock = secondLock;
}
@Override
public void run() {
try {
firstLock.lockInterruptibly();
secondLock.lockInterruptibly();
} catch (InterruptedException e) {
if(e instanceof InterruptedException) System.out.println(Thread.currentThread().getName() + "响应了中断");
else e.printStackTrace();
} finally {
firstLock.unlock();
secondLock.unlock();
System.out.println(Thread.currentThread().getName()
+"获取到了资源,正常结束!");
}
}
}
}

运行结果

如果线程0使用lockInterruptibly()来获取锁,可以看到阻塞后调用中断方法时它会主动中断,然后释放锁,让线程1得以完成,但是使用lock()来获取锁,则不会响应中断,最后请求互斥形成死锁。