簡述
我們知道使用ReentrantLock可以實(shí)現(xiàn)同步,保證線程安全,下面我們來簡單實(shí)現(xiàn)自己的Lock
實(shí)現(xiàn)
我們最常使用,也最為重要的就是Lock中的lock()和unlock()方法,因此我們只簡單實(shí)現(xiàn)這兩個(gè)方法,代碼如下
package test;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @author baipengfei
* @version 1.0
* @description TODO
* @date 19-1-6 上午11:20
**/
public class MyLock implements Lock {
private boolean isHoldLock = false;
/**
* 同一時(shí)刻,只有一個(gè)線程獲取到鎖
*/
@Override
synchronized public void lock() {
if(isHoldLock){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isHoldLock = true;
}
@Override
synchronized public void unlock() {
notify();
isHoldLock = false;
}
}
當(dāng)?shù)谝粋€(gè)線程進(jìn)行lock時(shí),跳過if,將isHoldLock設(shè)為true,其他線程在lock時(shí)就會(huì)wait等待,直到調(diào)用unlock,notify()將等待的線程喚醒,isHoldLock設(shè)為false是因?yàn)橛锌赡芤粋€(gè)線程速度很快,直接lock到unlock一步完成,過程中沒有其他線程調(diào)用lock,所以需要保證結(jié)束后其他線程可以正常調(diào)用lock獲得鎖
缺點(diǎn)
上述代碼簡單實(shí)現(xiàn)了一個(gè)Lock,但是這種Lock不是可重入的,即對(duì)象在一個(gè)線程內(nèi)無法再次獲得自己內(nèi)部的鎖,如下例子
package test;
import java.util.concurrent.locks.Lock;
/**
* @author baipengfei
* @version 1.0
* @description 測試是否可重入
* @date 19-1-6 上午11:41
**/
public class ReentryDemo {
private Lock lock = new MyLock();
public void methodA(){
lock.lock();
System.out.println("進(jìn)入方法A");
methodB();
lock.unlock();
}
public void methodB(){
lock.lock();
System.out.println("進(jìn)入方法B");
lock.unlock();
}
public static void main(String[] args) {
new ReentryDemo().methodA();
}
}
methodA等待methodB結(jié)束,而methodB在等待methodA釋放鎖,導(dǎo)致類似與死鎖的情況(其實(shí)不是死鎖)。
解決
下面我們來繼續(xù)改進(jìn)代碼,實(shí)現(xiàn)可重入性
package test;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @author baipengfei
* @version 1.0
* @description TODO
* @date 19-1-6 上午11:20
**/
public class MyLock implements Lock {
private boolean isHoldLock = false;
private Thread holdLockThread = null;
private int reentryCount = 0;
/**
* 同一時(shí)刻,只有一個(gè)線程獲取到鎖
*/
@Override
synchronized public void lock() {
if(isHoldLock && Thread.currentThread() != holdLockThread){
//當(dāng)被鎖住時(shí),判斷一下是不是同一線程鎖的,不是就給我等!
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
holdLockThread = Thread.currentThread();
isHoldLock = true;
reentryCount ++;
}
@Override
synchronized public void unlock() {
//判斷當(dāng)前線程是否是持有鎖的線程 是 重入次數(shù)-1 否 不作處理
if(holdLockThread == Thread.currentThread()){
reentryCount --;
if (reentryCount == 0){
//全部解鎖完畢再喚醒其他線程
notify();
isHoldLock = false;
}
}
}
}
- holdLockThread 用來判斷再次lock時(shí),是否是同一線程進(jìn)行l(wèi)ock,如果不是,就等待吧!
- reentryCount用來判斷重入次數(shù),因?yàn)橹厝攵啻?,即lock多次后,必須有相同數(shù)量的unlock才算解鎖完畢!其他線程才可以拿到鎖