版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kevin_King1992/article/details/79813078
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @author Kevin @date 2017-12-19
*
* 自定义独占锁实现。
*
*/
public class MyLock implements Lock {
/**
* @author Kevin
*
* 利用同步器AbstractQueuedSynchronizer这一线程安全的基础组件,完成独占锁的实现。
* AbstractQueuedSynchronizer作为 同步基础组件 而设计,这也是设计者的初衷,让程序员利用它完成更多同步工作。
*
* AbstractQueuedSynchronizer实现分析:(来自于并发编程的艺术一书)
* AQS中的静态内部类Node(当前线程和等待状态等信息、前后驱节点信息)是构成同步队列的基础。
*
* 同步队列是遵循FIFO,入队进队尾,这个过程需要借助CAS保证线程安全,因此提供了compareAndSetTail()的方法。
* 获取到同步状态的首节点在释放同步状态的同时,后继节点将会获取同步状态并且置位首节点。此过程是不需要CAS操作的,
* 因为获取同步状态的只有一个线程,不存在问题。
*
*
*/
private static class Sync extends AbstractQueuedSynchronizer {
/**
*
*/
private static final long serialVersionUID = 1L;
//是否处于占用状态
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
//当状态为0 的时候获取锁
@Override
protected boolean tryAcquire(int arg) {
if(compareAndSetState(0, 1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
//释放锁,将状态设置为 0
@Override
protected boolean tryRelease(int arg) {
if(getState() == 0)
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
Condition newCondition(){
return new ConditionObject();
}
}
private final Sync sync = new Sync();
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
public boolean isLocked(){
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads(){
return sync.hasQueuedThreads();
}
}