JDK併發包--重入鎖
重入鎖基本使用:
使用java.util.concurrent.locks.ReentrantLock 類來實現,可以替代synchronized關鍵字。如下例,重入鎖有著顯示的操作過程,開發者可以手動指定在哪裡加鎖,在哪裡釋放(退出臨界區時必須釋放,不然其他執行緒沒有機會再訪問了)。重入的意思是,同一個執行緒可以多次獲得鎖,同樣的退出時需要多次釋放。
public class LockDemo implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
public static int i=0;
public finnal int N= 10000;
@Override
public void run(){
for(int j=0;j<N;j++){
lock.lock(); //加鎖
lock.lock();
try(
i++;
)finally{
lock.unlock(); //釋放鎖
lock.unlock();
}
}
}
public static void main(String[] args){
LockDemo tLock = new LockDemo();
Thread t1 = new Thread(tLock);
Thread t2 = new Thread(tLock);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(i);//最終輸出20000
}
}
中斷響應:
對鎖的請求使用lockInterruptibly()方法,可以在等待鎖的過程中響應中斷
package com.test;
import java.util.concurrent.locks.ReentrantLock;
public class IntruptLock implements Runnable{
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lock;//控制加鎖順序,方便構成死鎖
public IntruptLock(int lock){this.lock = lock;}
public void run(){
try{
if(lock==1){
while(true){
lock1.lockInterruptibly();
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
}
lock2.lockInterruptibly();
}
}else {
while(true){
lock2.lockInterruptibly();
try {
Thread.sleep(1000);
}catch(InterruptedException e) {
lock1.lockInterruptibly();
}
}
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
if(lock1.isHeldByCurrentThread()) {
lock1.unlock();
}
if(lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
System.out.println(Thread.currentThread().getName()+":執行緒退出");
}
}
public static void main(String[] args) throws InterruptedException {
IntruptLock r1 = new IntruptLock(1);
IntruptLock r2 = new IntruptLock(2);
//t1先獲得lock1鎖,再申請lock2,t2先獲得lock2鎖,再申請lock1,構成死鎖
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
Thread.sleep(1000);
t2.interrupt();//中斷t2,lock2響應中斷,t2釋放lock2鎖,t1得以執行下去
}
}
tryLock():
仍然是上個栗子,如果使用的是tryLock(),t2在申請lock1時沒有獲得,它不會傻傻的等,而是會立刻返回false,然後繼續執行重新嘗試,只要時間夠長,總會獲得lock1而執行下去。
tryLock()也可以傳入引數,tryLock(10,TimeUnit.SECONDS),分別表示時長和時間單位。
公平鎖:
public ReentrantLock(boolean fair),各執行緒獲得公平鎖的概率是相等的。