提出问题
解决
使用 ScheduledExecutorService (接口)、ScheduledThreadPoolExecutor(前面接口的实现类)替代 Timer
线程数可以自行控制,基于多线程机制,任务之间不会相互影响
介绍
ScheduledExecutorService :是接口
ScheduledThreadPoolExecutor :是上面接口的实现类,该类继承 ThreadPoolExecutor 类
创建对象
创建 ScheduledThreadPoolExecutor 对象,有两种方法:
通过
ScheduledThreadPoolExecutor构造方法Executors工厂方法创建
根据阿里巴巴代码规范中的建议,推荐使用第一种方式
通过 构造方法 创建对象
参数最全的构造方法:
ScheduledThreadPoolExecutor(
int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
)
参数解释:
corePoolSize:核心线程数量threadFactory:线程工厂,用来创建线程,默认为Executors.defaultThreadFactory()handler: 拒绝策略,默认为 AbortPolicy 中止策略
底层代码
上面构造方法,底层在调用 ThreadPoolExecutor 类的构造方法,如下:
super(
corePoolSize, // 形参传入
Integer.MAX_VALUE, // 最大线程数
0, // 空闲线程存活时间
NANOSECONDS, // 空闲线程存活时间 的单位,纳秒
new DelayedWorkQueue(), // 任务队列,使用内部类
threadFactory, // 线程工厂
handler // 拒绝策略
);
通过 Executors 创建对象
注意:不要使用该方式,详见 链接
通过 newSingleThreadScheduledExecutor() 方法
通过 newSingleThreadScheduledExecutor() 方法创建对象,这个对象的线程池大小为 1 ,如果任务多于一个,任务将按先后顺序执行,即:串行
方式一
Executors.newSingleThreadScheduledExecutor()
方式二
Executors.newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
参数解释:
ThreadFactory:线程工厂,用于自定义线程的名字,daemon,优先级等
- 可以使用
Executors.DefaultThreadFactory类对象 - 也可以自定义,实现
ThreadFactory接口
- 可以使用
通过 newScheduledThreadPool() 方法
创建对象,可以指定线程池大小
方法一
Executors.newScheduledThreadPool(int corePoolSize);
参数解释:
- corePoolSize:线程数量
方法二
Executors.newScheduledThreadPool(
int corePoolSize,
ThreadFactory threadFactory
);
参数解释:
corePoolSize:线程数量
ThreadFactory:线程工厂,用于自定义线程的名字,daemon,优先级等
- 可以使用
Executors.DefaultThreadFactory类对象 - 也可以自定义,实现
ThreadFactory接口
- 可以使用
常用功能方法
定时执行任务的方法:
- schedule()
- scheduleAtFixedRate()
- scheduleWithFixedDelay()
停止任务的方法,详见 shutdown() 、 shutdownNow()
schedule方法
延时执行任务,仅执行一次
schedule(
Runnable command, // Runnable实现类
long delay, // 延迟时间
TimeUnit unit // 延迟时间单位
)
例子
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test_schedule {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println(sdf.format(new Date()));
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(new Runnable() {
@Override
public void run() {
try {
System.out.println("run..."+sdf.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
}
},3, TimeUnit.SECONDS);//延迟3秒后执行 run() 方法,仅执行一次
// 可以调用 shutdown() 方法
executor.shutdown();
}
}
执行结果:
17:25:59
run...17:26:02 // 延迟3秒执行,且执行一次
schedule方法2
延时执行任务,仅执行一次,执行后可通过 Future.get() 阻塞直至任务执行完毕,并且可以获取执行结果
schedule(
Callable<V> callable, // Callable实现类
long delay, // 延迟时间
TimeUnit unit // 延迟时间单位
)
scheduleAtFixedRate 方法
循环任务,按照 上一次任务的开始时间 计算 下一次任务的开始时间
例子
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test_scheduleAtFixedRate {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println(sdf.format(new Date()));
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始执行..."+sdf.format(new Date()));
Thread.sleep(2000);
System.out.println("结束执行..."+sdf.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
}
},3,5, TimeUnit.SECONDS);//延迟3秒后执行第一次 run() 方法,之后每隔 5 秒执行一次 run() 方法
// 不能调用 shutdown() 方法,否则直接退出
// executor.shutdown();
}
}
执行结果:
19:03:14
开始执行...19:03:17 // 延迟3秒执行
结束执行...19:03:19 // 任务执行2秒
开始执行...19:03:22 // 本次任务开始执行时间 = 上次任务开始执行时间 + 5秒
结束执行...19:03:24
......
scheduleWithFixedDelay
循环任务,以 上一次任务的 结束时间 计算 下一次任务的开始时间
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test_scheduleWithFixedDelay {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println(sdf.format(new Date()));
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始执行..."+sdf.format(new Date()));
Thread.sleep(2000);
System.out.println("结束执行..."+sdf.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
}
},3,5, TimeUnit.SECONDS);//延迟3秒后执行第一次 run() 方法,之后每隔 5 秒执行一次 run() 方法
// 不能调用 shutdown() 方法,否则直接退出
// executor.shutdown();
}
}
执行结果:
19:07:31
开始执行...19:07:34 // 延迟3秒执行
结束执行...19:07:36 // 任务执行2秒
开始执行...19:07:41 // 本次任务开始执行时间 = 上次任务结束执行时间 + 5秒
结束执行...19:07:43
...
多线程对象
可以并行执行多个任务,创建对象方式不同,使用方法相同
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test_scheduleAtFixedRate {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println(sdf.format(new Date()));
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始执行任务1..."+sdf.format(new Date()));
Thread.sleep(2000);
System.out.println("结束执行任务1..."+sdf.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
}
},3,5, TimeUnit.SECONDS);//延迟3秒后执行第一次 run() 方法,之后每隔 5 秒执行一次 run() 方法
executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始执行任务2..."+sdf.format(new Date()));
Thread.sleep(2000);
System.out.println("结束执行任务2..."+sdf.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
}
},1,3, TimeUnit.SECONDS);//延迟3秒后执行第一次 run() 方法,之后每隔 5 秒执行一次 run() 方法
// 不能调用 shutdown() 方法,否则直接退出
// executor.shutdown();
}
}
参考:
https://www.jianshu.com/p/aeb391e4edb0
https://blog.csdn.net/xixisi888/article/details/108602699
https://www.jianshu.com/p/aeb391e4edb0