七、J.U.C

发布时间 2023-09-10 16:19:02作者: archaique

AQS

全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架

特点:

  • 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁
    • getState - 获取 state 状态
    • setState - 设置 state 状态
    • compareAndSetState - cas 机制设置 state 状态
  • 独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源 提供了基于 FIFO 的等待队列,类似于 Monitor 的 EntryList 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet(AQS 是 Java 实现,sychronized 是 c++ 实现)

用 AQS 自定义不可重入锁

tryAcquire 在 AQS 原代码里是可重入锁,这里继承了 AQS,将其重写为不可重入锁了

不可重入锁:本线程加了锁,那么后续本线程还想继续加锁,加锁是不成功的

final class MySync extends AbstractQueuedSynchronizer {
 
     @Override
     protected boolean tryAcquire(int acquires) {
      // int acquires 是可重入锁用来计数的。现在不可重入锁暂时用不到
         if (acquires == 1){
        // 通过设置 aqs 的 state 获得锁,初始值0,改为1代表获得了锁
        // 为了防止其它线程一起来修改 state 状态,所以用 compareAndSet
             if (compareAndSetState(0, 1)) {
          // 加锁成功后,设置 owner 线程为当前线程
             setExclusiveOwnerThread(Thread.currentThread());
          return true;
         }
      }
     // CAS 失败,即加锁失败
     return false;
   }
  @Override   
protected boolean tryRelease(int acquires) {     if(acquires == 1) {       // state=0表示当前没加锁,却要释放,抛出异常       if(getState() == 0) {         throw new IllegalMonitorStateException();       }       // 置空当前线程。ExclusiveOwnerThread 在 AQS 里不是 volatile 的       setExclusiveOwnerThread(null);       // state 在 AQS 里是 volatile 的,所以要放在后面,加写屏障,防止之前的指令重排       setState(0);       return true;     }     return false;    }
  
protected Condition newCondition() {     // aqs 提供的类     return new ConditionObject();    }
  @Override   
protected boolean isHeldExclusively() {     // 是否持有独占锁     return getState() == 1;   } }

原代码里的 acquire ,用 tryAcquire 尝试获取锁不成功,就放入等待队列中添加到一个链表中,并 LockSupport.park(this)

我们重写了 tryAcquire 方法为不可重入锁,所以这里的尝试获取锁会调用我们重写的方法,即获取不可重入锁

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
}

原代码里的 release,用 tryRelease 尝试释放锁成功后,还会唤醒等待队列上的线程从链表中移除,并用 LockSupport.unpark(node.thread) 唤醒

我们重写了 tryRelease 方法为不可重入锁释放,所以这里的尝试释放锁会调用我们重写的方法,即释放不可重入锁

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
}

对 MySync 的封装

class MyLock implements Lock {
 static MySync sync = new MySync();

 @Override
 // 尝试获取锁(被重写的tryAcquire),不成功,进入等待队列(AQS的逻辑)
 public void lock() {
 sync.acquire(1);
 }

 @Override
 // 尝试,不成功,进入等待队列,可打断
 public void lockInterruptibly() throws InterruptedException {
 sync.acquireInterruptibly(1);
 }

 @Override
 // 尝试一次,不成功返回,不进入队列(acquire 是 tryAcquire 进行的封装,失败会进入等待队列)
 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
 // 释放锁。tryRelease 只会释放锁,release 还会唤醒等待的线程
 public void unlock() {
 sync.release(1);
 }

 @Override
 // 生成条件变量
 public Condition newCondition() {
 return sync.newCondition();
 }
}

测试

MyLock lock = new MyLock();
new Thread(() -> {
   lock.lock();
   try {
     log.debug("locking...");
     sleep(1);
   } finally {
     log.debug("unlocking...");
     lock.unlock();
   }
},
"t1").start();
new Thread(() -> {   lock.lock();   try {     log.debug("locking...");   } finally {     log.debug("unlocking...");     lock.unlock(); } },"t2").start();