Java并发编程之ScheduledThreadPoolExecutor源码剖析

  之前我们剖析过Java中线程池ThreadPoolExecutor的源码,链接为 https://blog.csdn.net/HappyHeng/article/details/86827324,这一节从源码层次讲一下ScheduledThreadPoolExecutor这个定时线程池是如何执行任务的。

一、ScheduledFutureTask :

  在ThreadPoolExecutor中提交任务执行,只需要提交一个execute(Runnable)即可,ThreadPoolExecutor内部的queue也是存储Runnable即可。但是在定时线程池中,又将可执行的代码封装成一个ScheduledFutureTask,此Task中封装了Runnable的执行策略与执行时间,下面来看一下其成员变量:

private long time; // 此为下次执行时机的纳秒数

private final long period; // 重复任务的周期(以纳秒为单位)。正值表示固定速率的执行。负值表示固定延迟执行。值0表示非重复任务。

private Callable<V> callable; // 内部使用callable来保存传入的Runnable

下面讲一下线程拿到task后,其执行run()方法的解析:

        public void run() {
            boolean periodic = isPeriodic();
            // 当前的状态是否允许执行
            if (!canRunInCurrentRunState(periodic))
                cancel(false);
            // periodic表示固定时间段执行,若为!periodic,则表示不按固定时间段执行,只执行一次即可
            else if (!periodic)
                ScheduledFutureTask.super.run();
            // 若为periodic,则调用父类的runAndReset()执行相关代码
            else if (ScheduledFutureTask.super.runAndReset()) {
                // 执行完成后,设置下一次执行的时间,将时间设置到time字段中
                setNextRunTime();
                // 将task重新插入到queue队列中
                reExecutePeriodic(outerTask);
            }
        }

 

二、DelayedWorkQueue:

  看完了ScheduledFutureTask之后,我们知道Task分为只执行一次与固定速率执行的两种task,那么定时线程池是如何等待指定时间才去执行task呢?

  我们知道,在ThreadPoolExecutor中,线程池会阻塞在blockQueue中,直到有runnable存入。而ScheduledFutureTask中,是新写了支持延时执行的Queue来达到定时执行的目的,即为DelayedWorkQueue,我们看一下其take()方法:

        public RunnableScheduledFuture<?> take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
	    	// 在执行之前首先要获取到锁
            lock.lockInterruptibly();
            try {
                for (;;) {
					// 在queue中,会根据执行时间将task排序,此为获取到第一个执行的task
                    RunnableScheduledFuture<?> first = queue[0];
                    if (first == null)
                    	// 如果queue中没有task,则一直等待
                        available.await();
                    else {
                    	// 得到第一个执行的task与现在时间的间隔
                        long delay = first.getDelay(NANOSECONDS);
                        if (delay <= 0)
                        	// 若小与等于0,说明需要买上执行,则返回此task
                            return finishPoll(first);
                        first = null; // don't retain ref while waiting
                        // leader为正在等待的线程
                        if (leader != null)
                        	// 如果此时有线程在等待,那么当前线程需要一直等待
                            available.await();
                        else {
                            Thread thisThread = Thread.currentThread();
                            leader = thisThread;
                            try {
                            	// 如果未有线程等待,则当前线程等待第一个task的执行时间
                                available.awaitNanos(delay);
                            } finally {
                                if (leader == thisThread)
                                    leader = null;
                            }
                        }
                    }
                }
            } finally {
            	// 当执行完成时,调用signal()来唤起其它线程
                if (leader == null && queue[0] != null)
                    available.signal();
                lock.unlock();
            }
        }

  上述简单的分析了ScheduledThreadPoolExecutor的等待与获取task的过程,以及task的执行过程,如果以后有时间的话,会以图画的形式来分析一下ScheduledThreadPoolExecutor的执行过程。

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值