ReentrantLock
與synchronized相比有以下特點
- 可中斷
- 可以設定為公平鎖
- 支援多個條件變數
與sychronized一樣的
- 支援可重入鎖
- 可打斷鎖(避免死鎖):使用lockInterruptibly()方法
public class TestReentrant {
private static ReentrantLock lock=new ReentrantLock();
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
System.out.println("嘗試獲取鎖");
//如果沒有競爭此方法會獲取鎖
//有競爭則進入阻塞佇列,可以被其他執行緒用interrupt方法打斷
lock.lockInterruptibly();
} catch (InterruptedException i) {
System.out.println("沒有獲取到鎖");
i.printStackTrace();
return;
}
try {
System.out.println("獲取鎖成功");
} finally {
lock.unlock();
}
});
lock.lock();
thread.start(); //主執行緒拿走鎖,使thread執行緒進入阻塞狀態
// thread.interrupt(); //打斷該執行緒避免死鎖
}
}
鎖超時
- 設定鎖超時
reentrantLock.tryLock(2, TimeUnit.SECONDS)//嘗試獲取鎖獲取鎖成功返回true,失敗返回false
reentrantLock.unLock();//該方法呼叫必須放在finally
條件變數:
可以建立多個,讓某個執行緒進入該條件變數等待。喚醒時可以指定喚醒某個執行緒
Condition condition = lock.newCondition(); //建立一個條件變數,讓某個執行緒在這裡等待
Condition condition1 = lock.newCondition();
try {
condition.await(); //讓執行緒進入等待
condition.signal(); //喚醒該條件變數中某個執行緒
condition.signalAll();//喚醒該條件變數中的全部執行緒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
結合上面寫個案例
package devise;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* 小明沒煙,要抽菸才能幹活
* 小紅餓了,要吃外賣才能幹活。
* 但是在同一個房間休息小明抽菸會有煙味,小紅吃不下。
* 所以分了兩房間
*
*/
public class TestCorrectPostureStep {
static ReentrantLock lock=new ReentrantLock();
static Condition c1=lock.newCondition();//房間c1
static Condition c2=lock.newCondition();//房間c2
static boolean cigarette =false;
static boolean takeout =false;
public static void main(String[] args){
//小明
Thread t1=new Thread(()->{
lock.lock();
try {
while (!cigarette){
System.out.println("煙沒到休息一會");
try {
c1.await(); //讓小明到c1休息室休息
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("煙到了,開始幹活");
} finally {
lock.unlock();
}
});
//小紅
Thread t2 =new Thread(()->{
lock.lock();
try {
while (!takeout){
System.out.println("外賣沒到休息一會");
try {
c2.await();//讓小紅到c2休息室休息
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("外賣到了,開始幹活");
}finally {
lock.unlock();
}
});
//送外賣執行緒
Thread t3=new Thread(()->{
lock.lock();
try {
Thread.sleep(2000);
cigarette=true;
c1.signal();//喚醒小紅讓小明幹活
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
});
//送煙執行緒
Thread t4=new Thread(()->{
lock.lock();
try {
Thread.sleep(2000);
takeout=true;
c2.signal(); //喚醒小明讓小明幹活
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
});
t1.start();
t2.start();
t3.start();
t4.start();
}}