快捷搜索:  汽车  科技

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进行标记的。

scheduled定时任务失效原因(ScheduledExecutorService原理分析)(1)

其实这两个循环的目的只有一个,就是获取当前线程是否可执行。

关键代码如下:

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();

此时该线程的任务开始执行。

猜您喜欢: