(java并发)ScheduledThreadPoolExcutor

*爱你&永不变心* 提交于 2020-03-02 04:33:01

1.用timer缺点非常大
 

Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度因此所有任务都是串行执行的,同一时间只能有一个任务在执行前一个任务的延迟或异常都将会影响到之后的任务。

 

我们关于定时/周期操作都是通过Timer来实现的。但是Timer有以下几种危险

a. Timer是基于绝对时间的。容易受系统时钟的影响。 
b. Timer只新建了一个线程来执行所有的TimeTask。所有TimeTask可能会相关影响 
c. Timer不会捕获TimerTask的异常,只是简单地停止。这样势必会影响其他TimeTask的执行。 


2.ScheduledThreadPoolExecutor

鉴于 Timer 的上述缺陷,Java 5 推出了基于线程池设计的ScheduledThreadPoolExecutor。其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需 要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。

 

有以下四个调度器的方法:

public ScheduledFuture<?> schedule(Runnable command,
				       long delay, TimeUnit unit);

public <V> ScheduledFuture<V> schedule(Callable<V> callable,
					   long delay, TimeUnit unit);

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
						  long initialDelay,
						  long period,
						  TimeUnit unit);

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
						     long initialDelay,
						     long delay,
						     TimeUnit unit);

那么这四个方法有什么区别呢?其实第一个和第二个区别不大,一个是Runnable、一个是Callable,内部包装后是一样的效果;所以把头两个方法几乎当成一种调度,那么三种情况分别是:

1、 进行一次延迟调度:延迟delay这么长时间,单位为:TimeUnit传入的的一个基本单位,例如:TimeUnit.SECONDS属于提供好的枚举信息;(适合于方法1和方法2)。

2、 多次调度,每次依照上一次预计调度时间进行调度,例如:延迟2s开始,5s一次,那么就是2、7、12、17,如果中间由于某种原因导致线程不够用,没有得到调度机会,那么接下来计算的时间会优先计算进去,因为他的排序会被排在前面,有点类似Timer中的:scheduleAtFixedRate方法,只是这里是多线程的,它的方法名也叫:scheduleAtFixedRate,所以这个是比较好记忆的(适合方法3)

3、 多次调度,每次按照上一次实际执行的时间进行计算下一次时间,同上,如果在第7秒没有被得到调度,而是第9s才得到调度,那么计算下一次调度时间就不是12秒,而是9+5=14s,如果再次延迟,就会延迟一个周期以上,也就会出现少调用的情况(适合于方法3);

4、 最后补充execute方法是一次调度,期望被立即调度,时间为空

public class ScheduledThreadPoolExecutorDemo {  
     
    public static void main(String[] args) {  
        ScheduledThreadPoolExecutor scheduledExecutor = new ScheduledThreadPoolExecutor(1);  
        /** 
         * new timeTaskForException() 要执行的任务线程 
         * 1000:延迟多长时间执行 
         * 2000: 每隔多少长时间执行一次 
         * TimeUnit.MILLISECONDS:时间单位 
         */  
        scheduledExecutor.scheduleAtFixedRate(new timeTaskForException(), 1000, 2000, TimeUnit.MILLISECONDS);  
        scheduledExecutor.scheduleAtFixedRate(new timeTaskForPrintSYSTime(), 1000, 3000, TimeUnit.MILLISECONDS);  
          
    }  
  
    static class  timeTaskForException implements Runnable{  
  
        public void run() {  
            throw new RuntimeException();  
        }  
          
    }  
      
    static class timeTaskForPrintSYSTime implements Runnable {  
          
        public void run() {  
            System.out.println(System.nanoTime());  
        }  
    }  
}  

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!