[Java] lock、tryLock和lockInterruptibly的差別

在Java中的Lock介面有lock、tryLock和lockInterruptibly三個功能很相近的method,看完javadoc後還是搞不太清楚它們之間的差異性,終於找到一篇解釋清楚的文章了。

  • lock():若lock被thread A取得,thread B會進入block狀態,直到取得lock。
  • tryLock():若當下不能取得lock,thread就會放棄。
  • lockInterruptibly():跟lock()情況一下,但是thread B可以透過interrupt被喚醒處理InterruptedException。

範例:

  • 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
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo {
private final ReentrantLock lock;

public LockDemo() {
lock = new ReentrantLock();
}

public static void main(String[] args) throws InterruptedException {
LockDemo lockDemo = new LockDemo();
Runnable runnable = new Runnable() {
@Override
public void run() {
lockDemo.lock.lock();
System.out.println(String.format("%s %s locked", new Date(System.currentTimeMillis()), Thread.currentThread().getName()));
}
};
Thread threadA = new Thread(runnable, "Thread A");
Thread threadB = new Thread(runnable, "Thread B");

threadA.start();
threadB.start();
}
}

可以發現ThreadB呈現block狀態,一直在等待Thread A釋放lock。

  • tryLock():
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
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

public class TryLockDemo {
private final ReentrantLock lock;

public TryLockDemo() {
lock = new ReentrantLock();
}

public static void main(String[] args) throws InterruptedException {
TryLockDemo lockDemo = new TryLockDemo();
Runnable runnable = new Runnable() {
@Override
public void run() {
if (lockDemo.lock.tryLock()) {
System.out.println(String.format("%s %s locked", new Date(System.currentTimeMillis()), Thread.currentThread().getName()));
}
}
};
Thread threadA = new Thread(runnable, "Thread A");
Thread threadB = new Thread(runnable, "Thread B");

threadA.start();
threadB.start();
}
}

若一開始lock被Thread A取得,Thread B透過tryLock()當下若沒有取得到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
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

public class LockInterruptiblyDemo {
private final ReentrantLock lock;

public LockInterruptiblyDemo() {
lock = new ReentrantLock();
}

public static void main(String[] args) throws InterruptedException {
LockInterruptiblyDemo lockDemo = new LockInterruptiblyDemo();

Runnable runnable = new Runnable() {
@Override
public void run() {
try {
lockDemo.lock.lockInterruptibly();
System.out.println(String.format("%s %s locked", new Date(System.currentTimeMillis()), Thread.currentThread().getName()));
}
catch (InterruptedException e) {
System.out.println(String.format("%s %s interrupted", new Date(System.currentTimeMillis()), Thread.currentThread().getName()));
}
}
};
Thread threadA = new Thread(runnable, "Thread A");
Thread threadB = new Thread(runnable, "Thread B");

threadA.start();
Thread.sleep(1000);
threadB.start();
threadB.interrupt();
}
}

Thread A先取得lock,Thread B無法取得lock進入block狀態,可以透過發出interrupt方式喚醒Thread B。

Lock和synchronized幾乎是大同小異,但是Lock可以做更細微的同步方式。

參考資料:

用通俗的語言說說lock和lockInterruptibly的區別