之所以要使用线程池,是因为使用new Thread在大型项目中是有弊端的:
而线程池的好处:
还有很多其他的方法:比如:getQueue() 、getPoolSize() 、getActiveCount()、getCompletedTaskCount()等获取与线程池相关属性的方法,可以用于线程池监控,有兴趣的朋友可以自行查阅API。
更多ThreadPoolExecutor配置的详细说明,点击查看:还在用Executors创建线程池?小心内存溢出
@Slf4j
public class ThreadPoolExample {
public static void main(String[] args) {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
// 延时任务
// executorService.schedule(()->
// log.warn("schedule run"), 3, TimeUnit.SECONDS);
// 固定速率任务
executorService.scheduleAtFixedRate(()
-> log.warn("schedule run"), 1, 3, TimeUnit.SECONDS);
// executorService.shutdown();
// Timer也能执行定时任务,不过还是推荐用ScheduledExecutorService
// Timer timer = new Timer();
// timer.schedule(new TimerTask() {
// @Override
// public void run() {
// log.warn("timer run");
// }
// }, new Date(), 5 * 1000);
}
}
特别提示:通过ScheduledExecutorService执行的周期任务,如果任务执行过程中抛出了异常,那么ScheduledExecutorService就会停止执行任务,而且也不会再周期地执行该任务了。所以如果想保持任务周期执行,需要catch一切可能的异常。
CPU密集型任务:尽量压榨CPU,参考值设置为NCPU+1 IO密集型任务:参考值可以设置为2*NCPU
TaskExecutor是Spring异步线程池的接口,继承Java.util.concurrent.Executor接口
Spring已经实现的异步线程池(TaskExecutor的实现类):
@Async所修饰的函数不要定义为static类型,这样异步调用不会生效