AbstractQueuedSynchronizer是阻塞式的锁和相关同步器工具的框架,用state来标识状态,通过修改这个状态来标识获取锁和释放锁
getState - 获取锁的状态,setState - 来修改状态 ,compareAndSetState - 以cas的方式来修改值保证原子性,还提供了类似于synchronized的entryList阻塞队列和多个waitSet(synchronized只有一个waitSet)
@Slf4j(topic = "w.Test1")
public class Test1 {
public static void main(String[] args) {
MyLock myLock = new MyLock();
new Thread(() -> {
try {
myLock.lock();
log.debug("加锁");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
myLock.unlock();
log.debug("解锁");
}
}).start();
new Thread(() -> {
try {
myLock.lock();
log.debug("加锁");
} finally {
myLock.unlock();
log.debug("解锁");
}
}).start();
}
}
class MyLock implements Lock {
class MySync extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int arg) {
// 判断加锁是否成功 如果成功返回true 加锁失败返回false
// 使用cas保证原子性
if (compareAndSetState(0, 1)) {
// 设置当前线程为锁的主人
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
// 设置当前线程锁持有者为null
setExclusiveOwnerThread(null);
// 解锁 (因为只有锁的持有者才能释放锁所以释放这里可以不用cas保护)
// 把setState(0)放在setExclusiveOwnerThread 后面 因为state被volatile修饰
// volatile写屏障 保证前面的修改对其他线程可见,防止指令重拍 保证可见性和有序性
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {
// 判断是否是独占锁
return getState() == 1;
}
// 返回条件变量(waitSet)
protected Condition newCondition() {
return new ConditionObject();
}
}
MySync sync = new MySync();
@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() {
// 状态设置为0并唤醒阻塞的线程
sync.release(1);
}
@Override
public Condition newCondition() {
return newCondition();
}
}
lock
发现调用了一个acquire方法
而acquire正是调用我们重写的tryAcquire方法,如果加锁失败则调用acquireQueued会进入阻塞队列
发现在进入阻塞前还会继续尝试获得锁,如果获取到锁则停止自旋,如果没有获取到锁则加入node阻塞队列,并park阻塞线程
unlock
发现调用了我们之前重写的tryRelease方法
如果解锁成功从队列里面重新获取一个阻塞的线程判断锁状态进行唤醒