jdk1.8 AQS常用组件源码分析

AQS常用组件源码分析

这里主要介绍三种组件:Semaphore,CountDownLatch,CyclicBarrier

Semaphore

Semaphore代表一个共享式的信号量,资源可以同时被多个线程使用

属性

// 实现了AbstractQueuedSynchronizer的并发控制器
// 可以使用公平的,也可以是不公平的,通过构造函数的参数可以控制
private final Sync sync;

构造函数

// 通过fair参数判断是公平的还是不公平的
public Semaphore(int permits, boolean fair) {
   sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

下面主要介绍Sync和它的两个子类
Sync继承自AQS

abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;

	// 代表运行同时访问的线程个数
	// 底层是设置到AQS的状态中
    Sync(int permits) {
        setState(permits);
    }

    final int getPermits() {
        return getState();
    }

	// Sync中实现的是不公平的获取资源
	// 返回值如果大于等于0,代表资源获取成功,否则代表资源获取失败,如果资源获取失败,当前线程会进入等待队列中
    final int nonfairTryAcquireShared(int acquires) {
        for (;;) {
        	// 获取当前剩余资源量
            int available = getState();
            // 计算获取资源后的剩余资源量
            int remaining = available - acquires;
			// 如果剩余资源量小于0,直接返回
			// 如果剩余资源量大于零,使用cas更新剩余资源直到成功,或者在重复尝试更新资源剩余量的过程中,资源不量小于0,那么直接返回
			// 从这里也可以看出,这里是不公平的,因为当前线程直接申请资源,并且没有理会等待队列中是否有先于当前线程申请资源的线程
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }

	// 剩下的源码很简单就不分析了
	// 都是使用cas操作来更新资源量
    protected final boolean tryReleaseShared(int releases) {
        for (;;) {
            int current = getState();
            int next = current + releases;
            if (next < current) // overflow
                throw new Error("Maximum permit count exceeded");
            if (compareAndSetState(current, next))
                return true;
        }
    }

    final void reducePermits(int reductions) {
        for (;;) {
            int current = getState();
            int next = current - reductions;
            if (next > current) // underflow
                throw new Error("Permit count underflow");
            if (compareAndSetState(current, next))
                return;
        }
    }

    final int drainPermits() {
        for (;;) {
            int current = getState();
            if (current == 0 || compareAndSetState(current, 0))
                return current;
        }
    }
}
static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

    NonfairSync(int permits) {
        super(permits);
    }
	// 使用的就是父类Sync的方法
    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
}
// 公平的并发控制
static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

    FairSync(int permits) {
        super(permits);
    }
    protected int tryAcquireShared(int acquires) {
        for (;;) {
     		// 首先检查队列中是否有不止一个任务
     		// 如果有不止一个任务,还需要判断头结点的下一个任务是否是当前任务
     		// 只有在等待队列中没有任务,或者等待队列中只有一个任务,或者等待队列中的第二任务时当前任务时,当前任务可以获取资源   	
            if (hasQueuedPredecessors())
                return -1;
            int available = getState();
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }
}

获取与释放

获取和释放资源非常简单,底层调用的都是Sync子类相应的方法

public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}
public void release() {
    sync.releaseShared(1);
}

CountDownLatch

CountDownLatch的使用场景是这样的:一个线程需要等待一定数量的线程执行完毕之后,才能接着往下运行,否则将会阻塞,直到一定数量的线程执行完毕
其中多个线程在执行到某个位置时,会执行countdown来减小state
当state减小到0时,线程A被唤醒继续执行自己的任务
执行流程

构造函数

传入的参数代表需要等待多少个线程

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    // CountDownLatch中只有非公平的
    this.sync = new Sync(count);
}
private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

  Sync(int count) {
       setState(count);
   }

   int getCount() {
       return getState();
   }
   // 只有state等于0时,才能申请到资源
   protected int tryAcquireShared(int acquires) {
       return (getState() == 0) ? 1 : -1;
   }

   protected boolean tryReleaseShared(int releases) {
       // Decrement count; signal when transition to zero
       for (;;) {
           int c = getState();
           if (c == 0)
               return false;
           // 尝试减小state的值
           int nextc = c-1;
           if (compareAndSetState(c, nextc))
               return nextc == 0;
       }
   }
}

获取和释放

public void await() throws InterruptedException {
	// 底层会调用tryAcquiredShared方法
	// 如果state不为0,那么将当前线程加入等待队列中
	// 当state等于0时,会得到唤醒,从而继续执行线程的任务
    sync.acquireSharedInterruptibly(1);
}
public void countDown() {
	// 底层会调用tryReleaseShare()减小state的值
    sync.releaseShared(1);
}

CyclicBarrier

CyclicBarrier的使用场景是这样的:多个线程必须等待彼此到达某个执行位置时,才能一起往下执行,当且当指定的线程都到达了各自的目的位置时,可以另外执行一个任务,如果还有线程没有执行到各自的指定位置,那么就会阻塞等待其他任务执行到各自的指定位置
CyclicBarrier之所以叫Cyclic是因为,当所有线程都到代码的目的位置后,barrier释放,线程接着执行,会自动重新设置barrier,等待下一次所有线程执行各自的指定位置,即barrier可以循环使用
CyclicBarrier并没有使用AQS

属性

private static class Generation {
    boolean broken = false;
}

/** The lock for guarding barrier entry */
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();
/** The number of parties */
private final int parties;
/* The command to run when tripped */
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();

构造函数

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    // 代表需要等待多少个线程执行到指定位置
    this.parties = parties;
    // 剩余未到达指定位置的线程个数
    this.count = parties;
    // 当所有线程都执行到各自的指定位置时,除了释放barrier,让线程往下执行,还可以另外启动一个线程,就是下面指定的barrier释放动作
    this.barrierCommand = barrierAction;
}

获取和释放

当线程执行到指定位置需要等待其他线程时,会调用await()

public int await() throws InterruptedException, BrokenBarrierException {
   try {
       return dowait(false, 0L);
   } catch (TimeoutException toe) {
       throw new Error(toe); // cannot happen
   }
}
private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
  		// 一个generation代表一次完整的线程彼此等待过程
  		// 当线程都执行到各自的指定位置时,会调用generation的break(),来唤醒所有等待的线程,继续执行,
      final Generation g = generation;

      if (g.broken)
          throw new BrokenBarrierException();

      if (Thread.interrupted()) {
          breakBarrier();
          throw new InterruptedException();
      }

      int index = --count;
      // 所有的线程都已经达到了等待位置
      // 释放barrier
      // 当最后一个线程执行到指定位置,会唤醒其他所有等待线程
      if (index == 0) {  // tripped
          boolean ranAction = false;
          try {
              final Runnable command = barrierCommand;
              if (command != null)
                  command.run();
              ranAction = true;
              // 重新创建一个generation,并且唤醒所有的等待线程
              nextGeneration();
              return 0;
          } finally {
              if (!ranAction)
                  breakBarrier();
          }
      }

      // 一直循环直到所有线程都执行到了特定位置,或者遇到中断或者等待超时
      // 如果其他线程遇到中断也会导致barrier的broken,从而引起当前线程结束循环
      // 等待其他线程执行到指定位置
      for (;;) {
          try {
          		// 判断是否设置了等待时限
          		// 没有设置,就会一直等待
          		// 设置了,就会等待指定时间
              if (!timed)
                  trip.await();
              else if (nanos > 0L)
              		// 返回值代表剩余等待时间
              		// 返回值代表剩余等待时间
                  nanos = trip.awaitNanos(nanos);
          } catch (InterruptedException ie) {
              if (g == generation && ! g.broken) {
                  breakBarrier();
                  throw ie;
              } else {
                  // We're about to finish waiting even if we had not
                  // been interrupted, so this interrupt is deemed to
                  // "belong" to subsequent execution.
                  Thread.currentThread().interrupt();
              }
          }

          if (g.broken)
              throw new BrokenBarrierException();

          if (g != generation)
              return index;
	
			// 等待时间超时
			// 结束等待
          if (timed && nanos <= 0L) {
              breakBarrier();
              throw new TimeoutException();
          }
      }
  } finally {
      lock.unlock();
  }
}
// 如果没有中断也没有等待超时,所有线程都是正常执行到了指定位置,就会执行nextGenration
// 在该方法中会唤醒所有等待线程,重新计数,重新建立一个新的generation
private void nextGeneration() {
    // signal completion of last generation
    trip.signalAll();
    // set up next generation
    count = parties;
    generation = new Generation();
}
// 当因为中断或者等待超时而释放barrier时,会调用breakBarrier
// 此时并不会新建一个generation,只是会表示broken状态为true
// 同时也会唤醒所有线程,并且重新计数
private void breakBarrier() {
    generation.broken = true;
    count = parties;
    trip.signalAll();
}

总结一下流程:
(1)如果所有线程都正常的到达了指定的代码位置,就会运行barrier释放任务,并且重新设置generation以及count计数,所有等待线程接着往下执行,进入下一轮等待
(2)如果有线程等待超时或者被中断,标记generation为broken,唤醒所有等待线程并且抛出异常

猜你喜欢

转载自blog.csdn.net/lxlneversettle/article/details/88815124
今日推荐