赞
踩
} // 创建工作线程 workerThread = threadFactory.newThread(worker); // 非守护线程且 leakDetection 为 true 时检测内存是否泄漏 leak = leakDetection || !workerThread.isDaemon() ? leakDetector.track(this) : null; // 初始化最大等待任务数 this.maxPendingTimeouts = maxPendingTimeouts; // 如果创建的时间轮实例大于 64,打印日志,并且这个日志只会打印一次 if (INSTANCE_COUNTER.incrementAndGet() > INSTANCE_COUNT_LIMIT && WARNED_TOO_MANY_INSTANCES.compareAndSet(false, true)) { reportTooManyInstances(); } }
构造函数中的参数相当重要,当自定义时间轮时,我们应该根据业务的范围设置合理的参数: * threadFactory:创建时间轮任务线程的工厂,通过这个工厂可以给我们的线程自定义一些属性(线程名、异常处理等) * tickDuration:时钟多长时间拨动一次,值越小,时间轮精度越高 * unit:`tickDuration` 的单位 * ticksPerWheel:时间轮数组大小 * leakDetection:是否检测内存泄漏 * maxPendingTimeouts:时间轮内最大等待的任务数 时间轮的时钟拨动时长应该根据业务设置恰当的值,如果设置的过大,可能导致任务触发时间不准确。如果设置的过小,时间轮转动频繁,任务少的情况下加载不到任务,属于一直空转的状态,会占用 CPU 线程资源。 为了防止时间轮占用过多的 CPU 资源,当创建的时间轮对象大于 64 时会以日志的方式提示。 构造函数中只是初始化了轮线程,并没有开启,当第一次往时间轮内添加任务时,线程才会开启。 #### 2.3 往时间轮内添加任务
@Override public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { if (task == null) { throw new NullPointerException("task"); } if (unit == null) { throw new NullPointerException("unit"); } // 等待的任务数 +1 long pendingTimeoutsCount = pendingTimeouts.incrementAndGet(); // 如果时间轮内等待的任务数大于最大值,任务会被抛弃 if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) { pendingTimeouts.decrementAndGet(); throw new RejectedExecutionException("Number of pending timeouts (" + pendingTimeoutsCount + ") is greater than or equal to maximum allowed pending " + "timeouts (" + maxPendingTimeouts + ")"); } // 开启时间轮内的线程 start(); // 计算当前添加任务的执行时间 long deadline = System.nanoTime() + unit.toNanos(delay) - startTime; // Guard against overflow. if (delay > 0 && deadline < 0) { deadline = Long.MAX_VALUE; } // 将任务加入队列 HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline); timeouts.add(timeout); return timeout; }
任务会先保存在队列中,当时间轮的时钟拨动时才会判断是否将队列中的任务加载进时间轮。
public void start() {
switch (WORKER_STATE_UPDATER.get
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。