简述
我们知道使用ReentrantLock可以实现同步,保证线程安全,下面我们来简单实现自己的Lock
实现
我们最常使用,也最为重要的就是Lock中的lock()和unlock()方法,因此我们只简单实现这两个方法,代码如下
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;
/**
* 同一时刻,只有一个线程获取到锁
*/
@Override
synchronized public void lock() {
if(isHoldLock){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isHoldLock = true;
}
@Override
synchronized public void unlock() {
notify();
isHoldLock = false;
}
}
当第一个线程进行lock
时,跳过if
,将isHoldLock
设为true
,其他线程在lock
时就会wait
等待,直到调用unlock
,notify()
将等待的线程唤醒,isHoldLock
设为false
是因为有可能一个线程速度很快,直接lock
到unlock
一步完成,过程中没有其他线程调用lock
,所以需要保证结束后其他线程可以正常调用lock
获得锁
缺点
上述代码简单实现了一个Lock,但是这种Lock不是可重入的,即对象在一个线程内无法再次获得自己内部的锁,如下例子
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("进入方法A");
methodB();
lock.unlock();
}
public void methodB(){
lock.lock();
System.out.println("进入方法B");
lock.unlock();
}
public static void main(String[] args) {
new ReentryDemo().methodA();
}
}
methodA等待methodB结束,而methodB在等待methodA释放锁,导致类似与死锁的情况(其实不是死锁)。
解决
下面我们来继续改进代码,实现可重入性
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;
/**
* 同一时刻,只有一个线程获取到锁
*/
@Override
synchronized public void lock() {
if(isHoldLock && Thread.currentThread() != holdLockThread){
//当被锁住时,判断一下是不是同一线程锁的,不是就给我等!
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
holdLockThread = Thread.currentThread();
isHoldLock = true;
reentryCount ++;
}
@Override
synchronized public void unlock() {
//判断当前线程是否是持有锁的线程 是 重入次数-1 否 不作处理
if(holdLockThread == Thread.currentThread()){
reentryCount --;
if (reentryCount == 0){
//全部解锁完毕再唤醒其他线程
notify();
isHoldLock = false;
}
}
}
}
- holdLockThread 用来判断再次lock时,是否是同一线程进行lock,如果不是,就等待吧!
- reentryCount用来判断重入次数,因为重入多次,即lock多次后,必须有相同数量的unlock才算解锁完毕!其他线程才可以拿到锁