ScheduledExecutorService 和 Timer 的区别

Timer

schedule: 任务开始的时间 + period(时间片段),强调“固定间隔”地执行任务

scheduleAtFixedRate: 参数设定开始的时间 + period(时间片段),强调“固定频率”地执行任务

Timer的缺陷:

Timer被设计成支持多个定时任务,通过源码发现它有一个任务队列用来存放这些定时任务,并且启动了一个线程来处理。

通过这种单线程的方式实现,在存在多个定时任务的时候便会存在以下问题:

1、若任务A执行时间过长,将导致任务B延迟了启动时间!

2、若任务线程在执行队列中某个任务时,该任务抛出异常,将导致线程因跳出循环体而终止,即Timer停止了工作!

Timer示例说明:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
	public static void main(String[] args) {

		Timer timer = new Timer();

		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
				System.out.println(sdf.format(new Date()) + " Task1: do task");
			}
		}, 0, 1000);

		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
				System.out.println(sdf.format(new Date()) + " Task2: sleep");
				try {
					Thread.sleep(5 * 1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, 2 * 1000, 3000);

		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
				System.out.println(sdf.format(new Date()) + " Task3: throw Exception");
				throw new RuntimeException("test");
			}
		}, 10 * 1000, 5000);
	}

}

执行结果:

21:58:31 Task1: do task
21:58:32 Task2: sleep
21:58:37 Task1: do task
21:58:37 Task2: sleep
21:58:42 Task1: do task
Exception in thread "Timer-0" 21:58:42 Task3: throw Exception
java.lang.RuntimeException: test
	at com.learn.schedule.TimerTest$3.run(TimerTest.java:39)
	at java.util.TimerThread.mainLoop(Timer.java:555)
	at java.util.TimerThread.run(Timer.java:505)

ScheduledExecutorService示例:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;

public class ScheduleTest {
	public static void main(String[] args) {
		int corePoolSize = 3;
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(corePoolSize);

		pool.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
				System.out.println(sdf.format(new Date()) + " Task1: do task");
			}
		}, 0, 1, TimeUnit.SECONDS);

		pool.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
				System.out.println(sdf.format(new Date()) + " Task2: sleep");
				try {
					Thread.sleep(5 * 1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, 3, 3, TimeUnit.SECONDS);

		pool.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
				System.out.println(sdf.format(new Date()) + " Task3: throw Exception");
				throw new RuntimeException("test");
			}
		}, 10, 5, TimeUnit.SECONDS);
	}

}

corePoolSize =3 执行结果:

22:07:20 Task1: do task
22:07:21 Task1: do task
22:07:22 Task1: do task
22:07:23 Task1: do task
22:07:23 Task2: sleep
22:07:24 Task1: do task
22:07:25 Task1: do task
22:07:26 Task1: do task
22:07:27 Task1: do task
22:07:28 Task1: do task
22:07:28 Task2: sleep
22:07:29 Task1: do task
22:07:30 Task1: do task
22:07:30 Task3: throw Exception
22:07:31 Task1: do task

corePoolSize =1执行结果:

22:01:18 Task1: do task
22:01:19 Task1: do task
22:01:20 Task1: do task
22:01:21 Task1: do task
22:01:21 Task2: sleep
22:01:26 Task1: do task
22:01:26 Task1: do task
22:01:26 Task1: do task
22:01:26 Task2: sleep
22:01:31 Task1: do task
22:01:31 Task1: do task
22:01:31 Task1: do task
22:01:31 Task2: sleep
22:01:36 Task1: do task
22:01:36 Task3: throw Exception
22:01:36 Task1: do task
22:01:36 Task1: do task
22:01:36 Task2: sleep

1、将线程数设置为3,通过控制台打印可以看到Task1一直都在正常运行(任务时间间隔为1秒),并不受Task2的影响。Task3抛出异常后,虽然本身停止了调度,但没有影响到其他任务的调度。
2、将线程数设置为1,变成单线程跑时,结果和Timer一样,Task2会导致Task1延迟执行,但Task3抛异常不会影响到其他任务的调度。

参考
https://blog.csdn.net/guozebo/article/details/51090612 
 

你可能感兴趣的:(Java开发)