scheduled定时任务失效原因(ScheduledExecutorService原理分析)
scheduled定时任务失效原因(ScheduledExecutorService原理分析)下面我们在来看scheduleAtFixedRate 这个方法,源码如下:static class DelayedWorkQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable> { 通过跟踪源码分析可知,其实底层用的还是BlockingQueue(源码下篇分析),哈哈,看到这里是不是就很清楚了呢?//1秒后开始启动,每隔3s执行一次 service.scheduleAtFixedRate(new Runnable() { @Override public Void run() { System.out.println(Thread.currentThread().getName() "我开始执行了"); } } 1 3 TimeUnit.SECONDS);
最近跟别人聊天,别人问我了一个问题ScheduledExecutorService的原理是啥呢?
说实话,一脸懵逼的就过去了,虽然知道这么个东西,说实话也没细看实现的原理,今天就来分析一下吧。
我们先从一段代码开始今天的旅程。
ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
这里创建一个线程池为1的调度任务
//1秒后开始启动,每隔3s执行一次 service.scheduleAtFixedRate(new Runnable() { @Override public Void run() { System.out.println(Thread.currentThread().getName() "我开始执行了"); } } 1 3 TimeUnit.SECONDS);
这里每隔3便会执行一次Runnable。
这便是调度任务服务的简单实用方法,下面来仔细的分析一下源码。
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize Integer.MAX_VALUE 0 NANOSECONDS new DelayedWorkQueue()); }
进入源码可以看到这里的队列用的是延迟队列的实现。
static class DelayedWorkQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable> {
通过跟踪源码分析可知,其实底层用的还是BlockingQueue(源码下篇分析),哈哈,看到这里是不是就很清楚了呢?
下面我们在来看scheduleAtFixedRate 这个方法,源码如下:
/** * @throws RejectedExecutionException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command long initialDelay long period TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); if (period <= 0) throw new IllegalArgumentException(); ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command null triggerTime(initialDelay unit) unit.toNanos(period)); RunnableScheduledFuture<Void> t = decorateTask(command sft); sft.outerTask = t; delayedExecute(t); return t; }
仅仅从代码分析来看,delayedExecute(t); 这个才是关键代码,其实方法的名称已经表明了,老外方法命名真规范,一眼就看出来要干啥。
从897和898也基本能猜出来了,线程的状态是用AtomicInteger进行标记的。
其实这两个循环的目的只有一个,就是获取当前线程是否可执行。
关键代码如下:
if (compareAndIncrementWorkerCount(c)) break retry;
在这里可以看到,通过CAS计算之后,才会跳出该循环。
这里先放个疑问出来,如果前一次的任务还没有执行完,这里CPU会不会一直轮空?会不会造成cpu的飙升?
退出上面的循环后,实例化一个Worker 对象之后,进入了锁控制的部分,此处可以保证原子化。
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; }
从这里可以看出,增加一个worker对象的前提是线程的状态为:
rs < SHUTDOWN ||(rs == SHUTDOWN&& firstTask == null))
然后调用t.start();
此时该线程的任务开始执行。