天天看点

多线程学习(2):ScheduledThreadPoolExecutor 与 schedule 之小结

2018年7月9日08:48:58

欢迎扫二维码关注公众号,获取技术干货

【1】前言

    线程池与任务定时执行,一是项目随处可见的一种技术,二是自己还需打打扎实基础;不可以仅仅局限于业务的实现,要去体会底层的思想;

【2】关于线程池ThreadPoor与Timer的使用

2.1    Java提供的Time类可以周期性地或者延期执行任务,但是有时我们需要并行执行同样的任务,这个时候如果创建多个Time对象会给系统带来负担,解决办法是将定时任务放到线程池中执行。

    Java的ScheduledThreadPoolExecutor类实现了ScheduledExecutorService接口中定义的以不同方法执行任务的方法。

2.2 ScheduleThreadPoolExecutor与Timer相比的优势

(1)Timer是基于绝对时间的延时执行或周期执行,当系统时间改变,则任务的执行会受到的影响。而ScheduleThreadPoolExecutore中,任务时基于相对时间进行周期或延时操作。

(2)Timer也可以提交多个TimeTask任务,但只有一个线程来执行所有的TimeTask,这样并发性受到影响。而ScheduleThreadPoolExecutore可以设定池中线程的数量。

(3)Timer不会捕获TimerTask的异常,只是简单地停止,这样势必会影响其他TimeTask的执行。而ScheduleThreadPoolExecutore中,如果一个线程因某些原因停止,线程池可以自动创建新的线程来维护池中线程的数量。

2.3 自jdk1.5开始,Java开始提供ScheduledThreadPoolExecutor类来支持周期性任务的调度,在这之前,这些工作需要依靠Timer/TimerTask或者其它第三方工具来完成。但Timer有着不少缺陷,如Timer是单线程模式,调度多个周期性任务时,如果某个任务耗时较久就会影响其它任务的调度;如果某个任务出现异常而没有被catch则可能导致唯一的线程死掉而所有任务都不会再被调度。ScheduledThreadPoolExecutor解决了很多Timer存在的缺陷。JDK1.5之前的Timer和TimerTask类已经过时了。

通过如上的介绍,可以对比一下Timer和ScheduledThreadPoolExecutor:

Timer ScheduledThreadPoolExecutor
单线程 多线程
单个任务执行时间影响其他任务调度 多线程,不会影响
基于绝对时间 基于相对时间
一旦执行任务出现异常不会捕获,其他任务得不到执行 多线程,单个任务的执行不会影响其他线程

所以,在JDK1.5之后,应该没什么理由继续使用Timer进行任务调度了。

【3】ScheduledThreadPoolExecutor 工作原理

多线程学习(2):ScheduledThreadPoolExecutor 与 schedule 之小结

【4】源码

多线程学习(2):ScheduledThreadPoolExecutor 与 schedule 之小结

【5】实现例子

BusinessPool.java:

package test2;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class BusinessPool {
  
   private ScheduledThreadPoolExecutor executor;
      
      BusinessPool() {
      }
    
    public static class BusinessPoolThreadFactory implements ThreadFactory {
      final ThreadGroup group = Thread.currentThread().getThreadGroup();
          final AtomicInteger threadNumber = new AtomicInteger(1);
          final String namePrefix = "business-pool";
          
          @Override
          public Thread newThread(Runnable r) {
              Thread t = new Thread(group, r,
                                    namePrefix + threadNumber.getAndIncrement(),
                                    0);
              if (t.isDaemon())
                  t.setDaemon(false);
              if (t.getPriority() != Thread.NORM_PRIORITY)
                  t.setPriority(Thread.NORM_PRIORITY);
              return t;
          }
    }
    
      public void init() {
        this.executor = new ScheduledThreadPoolExecutor(1, new BusinessPoolThreadFactory());
      }
   
      
      public void schedule(Runnable runnable, long delay, TimeUnit unit) {
          executor.schedule(runnable, delay, unit);
      }
      
      public void execute(Runnable runnable) {
          executor.execute(runnable);
      }
      
      
}      

test.java:

package test2;

import java.util.concurrent.TimeUnit;

public class test23 {

  public static void main(String[] args) {
    BusinessPool businessPool = new BusinessPool();
    businessPool.init();
    businessPool.schedule(new Runnable() {
      @Override
      public void run() {
        System.out.println("Hello world 0_0|||");
      }
    }, 3, TimeUnit.SECONDS);
  }

}      

输出结果(延时3s执行线程):

Hello world 0_0|||      

参考博文:https://www.jianshu.com/p/925dba9f5969