前言
继上次,手写了ReentrantLock ,但是仍然存在很多不完美的地方,以及很多漏洞,下面,我将着眼于漏洞处进行修补和升级。
上次源代码
package top.gunplan.utils.lock;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
public class GunReLock implements Lock {
private AtomicReference<thread> owner = new AtomicReference<>(null);
private BlockingQueue<thread> waitqueue = new LinkedBlockingQueue<>();
@Override
public void lock() {
if (owner.compareAndSet(null, Thread.currentThread())) {
//获取锁成功
} else {
waitqueue.offer(Thread.currentThread());
LockSupport.park();
lock();
//获取锁失败
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
if (owner.compareAndSet(Thread.currentThread(), null)) {
LockSupport.unpark(waitqueue.poll());
} else {
//释放锁失败,只有一种可能,当前线程不持有锁
}
}
@Override
public Condition newCondition() {
return null;
}
}
/<thread>/<thread>
以下过程我们要对这个锁进行升级
首先我们看到的是,trylock方法并没有实现,我们现在来进行实现一下:
@Override
public boolean tryLock() {
return owner.compareAndSet(null, Thread.currentThread())
}
我们的try lock目前变成了这个样子,trylock很简单,只需要判断能否替换成功就行,相应的lock方法发生了改变
if (tryLock()) {
//获取锁成功
} else {
waitqueue.offer(Thread.currentThread());
LockSupport.park();
lock();
//获取锁失败
}
lock中使用了trylock()实现了复用。下一步要实现 trylock 在一定时间内的函数
第一步,计算出时间的毫秒数
第二步,循环trylock()直到超时
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
long now = System.currentTimeMillis();
final long stoptime = unit.toNanos(time); //获取所需要时间
while (System.currentTimeMillis() - now < stoptime) {
if (tryLock()) {
return true;
}
TimeUnit.MICROSECONDS.sleep(200);
}
return false;
}
写到了这里,还有一个非常大的bug没有解决,也就是当lock()获取锁失败之后,还没有将thread加入等待队列之前,锁被释放,waitqueue的队首元素被唤醒,可是目前队列中没有元素,之后,调用lock的线程被加入队列并且被park,这样这个线程将会被永远锁住,再也见不到天日
public void lock() {
if (tryLock()) {
//快速获取锁成功
} else {
//#1
waitqueue.offer(Thread.currentThread());
if (tryLock()) {//再一次尝试获取锁,防止unlock快速在#1过程中快速释放
waitqueue.poll();
return;
} else {
//如果unlock在这里快速释放,queue 已经存在当前线程,
// 那么因为park的顺序无关性,所以并不会出现无尽等待
// 能够被成功唤醒
LockSupport.park();
}
lock();
//获取锁失败
}
}
下一节,我们使用aqs机制对于锁进行改进
閱讀更多 青峰科技 的文章