/**
   * Creates a new timer.
   *
   * @param threadFactory a {@link ThreadFactory} that creates a background {@link Thread} which is
   *     dedicated to {@link TimerTask} execution.
   * @param tickDuration the duration between tick
   * @param unit the time unit of the {@code tickDuration}
   * @param ticksPerWheel the size of the wheel
   */
  public HashedWheelTimer(
      ThreadFactory threadFactory, long tickDuration, TimeUnit unit, int ticksPerWheel) {

    if (threadFactory == null) {
      throw new NullPointerException("threadFactory");
    }
    if (unit == null) {
      throw new NullPointerException("unit");
    }
    if (tickDuration <= 0) {
      throw new IllegalArgumentException("tickDuration must be greater than 0: " + tickDuration);
    }
    if (ticksPerWheel <= 0) {
      throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel);
    }

    // Normalize ticksPerWheel to power of two and initialize the wheel.
    wheel = createWheel(ticksPerWheel);
    mask = wheel.length - 1;

    // Convert tickDuration to milliseconds.
    this.tickDuration = tickDuration = unit.toMillis(tickDuration);

    // Prevent overflow.
    if (tickDuration == Long.MAX_VALUE || tickDuration >= Long.MAX_VALUE / wheel.length) {
      throw new IllegalArgumentException("tickDuration is too long: " + tickDuration + ' ' + unit);
    }

    roundDuration = tickDuration * wheel.length; // 每一轮的时间

    workerThread = threadFactory.newThread(worker); // 创建一个线程

    // Misuse check
    misuseDetector.increase(); // 增加一个实例计数
  }
  /**
   * Creates a new instance.
   *
   * @param corePoolSize the maximum number of active threads
   * @param maxChannelMemorySize the maximum total size of the queued events per channel. Specify
   *     {@code 0} to disable.
   * @param maxTotalMemorySize the maximum total size of the queued events for this pool Specify
   *     {@code 0} to disable.
   * @param keepAliveTime the amount of time for an inactive thread to shut itself down
   * @param unit the {@link TimeUnit} of {@code keepAliveTime}
   * @param threadFactory the {@link ThreadFactory} of this pool
   * @param objectSizeEstimator the {@link ObjectSizeEstimator} of this pool
   */
  public MemoryAwareThreadPoolExecutor(
      int corePoolSize,
      long maxChannelMemorySize,
      long maxTotalMemorySize,
      long keepAliveTime,
      TimeUnit unit,
      ObjectSizeEstimator objectSizeEstimator,
      ThreadFactory threadFactory) {

    super(
        corePoolSize,
        corePoolSize,
        keepAliveTime,
        unit,
        QueueFactory.createQueue(Runnable.class),
        threadFactory,
        new NewThreadRunsPolicy());

    if (objectSizeEstimator == null) {
      throw new NullPointerException("objectSizeEstimator");
    }
    if (maxChannelMemorySize < 0) {
      throw new IllegalArgumentException("maxChannelMemorySize: " + maxChannelMemorySize);
    }
    if (maxTotalMemorySize < 0) {
      throw new IllegalArgumentException("maxTotalMemorySize: " + maxTotalMemorySize);
    }

    allowCoreThreadTimeOut(true);

    settings = new Settings(objectSizeEstimator, maxChannelMemorySize);

    if (maxTotalMemorySize == 0) {
      totalLimiter = null;
    } else {
      totalLimiter = new Limiter(maxTotalMemorySize);
    }

    // Misuse check
    misuseDetector.increase();
  }
  @Override
  public synchronized Set<Timeout> stop() {
    if (Thread.currentThread() == workerThread) {
      throw new IllegalStateException(
          HashedWheelTimer.class.getSimpleName()
              + ".stop() cannot be called from "
              + TimerTask.class.getSimpleName());
    }

    if (!shutdown.compareAndSet(false, true)) {
      return Collections.emptySet();
    }

    boolean interrupted = false;
    while (workerThread.isAlive()) {
      workerThread.interrupt();
      try {
        workerThread.join(100);
      } catch (InterruptedException e) {
        interrupted = true;
      }
    }

    if (interrupted) {
      Thread.currentThread().interrupt();
    }

    misuseDetector.decrease();

    Set<Timeout> unprocessedTimeouts = new HashSet<Timeout>();
    for (Set<HashedWheelTimeout> bucket : wheel) {
      unprocessedTimeouts.addAll(bucket);
      bucket.clear();
    }

    return Collections.unmodifiableSet(unprocessedTimeouts);
  }
 @Override
 protected void terminated() {
   super.terminated();
   misuseDetector.decrease();
 }