什麼是可重入?
可重入鎖指的是可重複可遞歸調用的鎖,在外層使用鎖之後,在內層仍然可以使用,並且不發生死鎖(前提得是同一個對象或者class),這樣的鎖就叫做可重入鎖。ReentrantLock和synchronized都是可重入鎖。
一.在講解之前先介紹一下synchronized
synchronized是java內置的關鍵字,獲取和釋放鎖由JVM實現,非常方便。然而synchronized也有一定的侷限性。
- 當線程嘗試獲取鎖的時候,如果獲取不到鎖會一直阻塞。
- 如果獲取鎖的線程進入休眠或者阻塞,除非當前線程異常,否則其他線程嘗試獲取鎖必須一直等待。
JDK1.5之後發佈,加入了concurrent包。包內提供了Lock類,用來擴展的加鎖功能。Lock彌補了synchronized的侷限,提供了更加細粒度的加鎖功能。
二.ReentrantLock介紹
Lock lock = new ReentrantLock();
Lock是一個接口,ReentrantLock鎖是lock的一個實現
Lock接口的幾個方法的總體描述
/**
* 嘗試鎖
*/
package concurrent.t03;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test_02 {
Lock lock = new ReentrantLock();
void m1(){
try{
lock.lock();
for(int i = 0; i < 10; i++){
TimeUnit.SECONDS.sleep(1);
System.out.println("m1() method " + i);
}
//在lock和unlock之間可以調用m1()方法(遞歸調用),俗稱可重入。
// m1();
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
void m2(){
boolean isLocked = false;
try{
// 嘗試鎖, 如果有鎖,無法獲取鎖標記,返回false。
// 如果獲取鎖標記,返回true
// isLocked = lock.tryLock();
// 阻塞嘗試鎖,阻塞參數代表的時長,嘗試獲取鎖標記。
// 如果超時,不等待。直接返回。
isLocked = lock.tryLock(5, TimeUnit.SECONDS);
if(isLocked){
System.out.println("m2() method synchronized");
}else{
System.out.println("m2() method unsynchronized");
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(isLocked){
// 嘗試鎖在解除鎖標記的時候,一定要判斷是否獲取到鎖標記。
// 如果當前線程沒有獲取到鎖標記,會拋出異常。
lock.unlock();
}
}
}
public static void main(String[] args) {
final Test_02 t = new Test_02();
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
t.m2();
}
}).start();
}
}