1. 程式人生 > 其它 >6.23Java多執行緒可重入鎖實現原理

6.23Java多執行緒可重入鎖實現原理

6.23Java多執行緒可重入鎖實現原理

什麼是可重入鎖?

  • 某個執行緒試圖獲取一個已經由它自己持有的鎖時,這個請求會立刻成功

  • 將這個鎖的計數值+1.同時鎖住資源

  • 當執行緒退出同步程式碼塊時,計數器將會遞減。計數值=0時,鎖釋放

如果沒有可重入鎖,第二次獲得鎖時會進入死鎖狀態

鎖是作為併發共享資料,保證一致性的工具

之前用的鎖是內建鎖,內部已經設定好了。

可重入鎖程式碼示例

package thread.rearrangement;

/**
* 可重入鎖,鎖可以延續使用
* @since JDk 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class LockTest {

public void test(){

/**
* 第一次獲得鎖
*/
synchronized(this){
while(true){
/*第二次獲得同樣的鎖*/
synchronized(this){
System.out.println("ReentrantLock!");
}

try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}

}

public static void main(String[] args) {
new LockTest().test();
}
}

使用同步方法

class ReentrantLockTest{
public synchronized void a(){

}

public synchronized void b(){

}

/**
* 可重入鎖的用法
*/
public synchronized void all(){
this.a();
this.b();
}
}
不可重入鎖程式碼示例
package thread.rearrangement;

/**
* 不可重入鎖:表示鎖不可以延續使用--->迴圈
* @since JDK 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class LockTestNo2 {

/*使用鎖*/
Lock lock = new Lock();

/*成員方法*/
public void a() throws InterruptedException {
lock.lock();
doSomething();
lock.unlock();
}

/*不可重入--->屬性值不能往下面帶,用了鎖之後不會釋放掉*/
public void doSomething() throws InterruptedException {
lock.lock();
//......
lock.unlock();
}

public static void main(String[] args) throws InterruptedException {

LockTestNo2 testNo2 = new LockTestNo2();
testNo2.a();
testNo2.doSomething();
}

}

/**
* 自定義鎖的類:這是一個不可重入鎖
*/
class Lock{

/*表示是否被佔用的屬性*/
private boolean isLocked = false;

/*使用鎖的方法*/
public synchronized void lock() throws InterruptedException {
/*寫一個死迴圈*/
while (isLocked){
/*加入等待執行緒*/
wait();
}

/*鎖的狀態改變*/
isLocked = true;

}

/*釋放鎖的方法*/
public synchronized void unlock(){

/*屬性變為初始化*/
isLocked = false;

/*喚醒資源*/
notifyAll();

}

}
可重入鎖demo

實現原理:當執行緒請求鎖時先判斷進來的執行緒是否是當前已持有鎖的執行緒,如果是就直接使用。如果不是就等待

package thread.rearrangement;

/**
* 可重入鎖,鎖可以延續使用
* 鎖可以延續使用,每一個鎖都有一個計數器
* @since JDk 1.8
* @date 2021/6/23
* @author Lucifer
*/
public class LockTestNo3 {

/*使用鎖*/
ReLock reLock = new ReLock();

/*成員方法*/
public void a() throws InterruptedException {
reLock.lock();
System.out.println(reLock.getHoldCount());
doSomething();
reLock.unlock();
System.out.println(reLock.getHoldCount());
}

/*不可重入--->屬性值不能往下面帶,用了鎖之後不會釋放掉*/
public void doSomething() throws InterruptedException {
reLock.lock();
System.out.println(reLock.getHoldCount());
//......
reLock.unlock();
System.out.println(reLock.getHoldCount());
}

public static void main(String[] args) throws InterruptedException {

LockTestNo3 testNo3 = new LockTestNo3();
testNo3.a();

Thread.sleep(1000);

/*檢視計數器*/
System.out.println(testNo3.reLock.getHoldCount());
}

}

/**
* 自定義鎖的類:這是一個不可重入鎖
*/
class ReLock{

/*表示是否被佔用的屬性*/
private boolean isLocked = false;

/*加入一個儲存執行緒*/
private Thread lockedBy = null;

/*加入一個計數器,統計鎖的使用*/
private int holdCount = 0;

/*使用鎖的方法*/
public synchronized void lock() throws InterruptedException {

/*取當前執行緒變數*/
Thread t = Thread.currentThread();

/*寫一個死迴圈*/
while (isLocked&&lockedBy!=t){
/*加入等待執行緒*/
wait();
}

/*鎖的狀態改變*/
isLocked = true;

/*把t賦值給lockedBy*/
lockedBy = t;

/*計數器+1*/
holdCount++;

}

/*釋放鎖的方法*/
public synchronized void unlock(){

/*當前執行緒=自身的時候釋放鎖*/
if (Thread.currentThread()==lockedBy){

/*計數器自減少*/
holdCount--;

/*計數器為0時候釋放鎖*/
if (holdCount==0){

/*改變鎖狀態*/
isLocked = false;

/*喚醒資源*/
notify();

/*重置執行緒*/
lockedBy = null;

}
}

/*屬性變為初始化*/
isLocked = false;

/*喚醒資源*/
notifyAll();

}


/*提供get方法*/
public int getHoldCount() {
return holdCount;
}
}

JUC包下的ReentrantLock類實現了可重入鎖的操作