java线程池 - ScheduledThreadPoolExecutor的使用

什么是ScheduledThreadPoolExecutor?

在给定的延迟之后运行任务或者是定期执行任务
本文只简单描述一下怎么使用,不涉及原理和源码,可以简单了解后自己去撸源码。

构造

ScheduledThreadPoolExecutor(int corePoolSize)
ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler)
ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory)
ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler)

ScheduledThreadPoolExecutor方法

类型 方法 描述
protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) 修修改或替换用于执行可运行的任务
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) 修改或替换用于执行可运行的任务
void execute(Runnable command) 零延迟执行命令
boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() 获取执行程序已关闭是否继续执行现有定期任务的策略
boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() 获取执行程序已关闭是否执行现有延迟任务的策略
BlockingQueue<Runnable> getQueue() 返回执行程序使用的任务队列
boolean getRemoveOnCancelPolicy() 获取在取消时是否应立即从工作队列中删除已取消任务的策略
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) 创建并执行一次操作,该操作在给定延迟后启用
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) 创建并执行一个周期性操作,该操作在给定的初始延迟后首先启用,然后在给定的时间后再次启用,即第一次是initialDelay后执行,第二次是initialDelay + period后执行,第三次是 initialDelay + period*2 后执行,依次类推
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 创建并执行一个周期性动作,该动作在给定的初始延迟后首先启用,然后在一次执行的终止后开始,delay后开始执行下一次
void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) 设置执行程序关闭是否继续执行现有定期任务的策略
void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) 设置关闭后执行程序是否也执行现有延迟任务的策略
void setRemoveOnCancelPolicy(boolean value) 设置取消时任务时是否应立即从工作队列中删除已取消任务的策略
void shutdown() 启动有序关闭,在该关闭中执行先前提交的任务,但不接受任何新任务
List<Runnable> shutdownNow() 尝试停止所有正在执行的任务,暂停正在等待的任务的处理,并返回正在等待执行的任务的列表
<T> Future<T> submit(Callable<T> task) 提交有返回值的Callable任务
Future<?> submit(Runnable task) 提交有返回值的Runnable任务
<T> Future<T> submit(Runnable task, T result) 提交有返回值的Callable任务

ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,所以也继承了ThreadPoolExecutor方法,ThreadPoolExecutor有哪些方法可以去Java API规范中去查看,也可以到java线程池 - ThreadPoolExecutor中查看。

例子

  • schedule(Runnable command, long delay, TimeUnit unit)
    执行没有返回值的Runnable任务
package com.sy.thread.example;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;

/**
 * Description: thread
 *
 * @author songyu
 */
public class ScheduledThreadPoolExecutorTest {
    public static void main(String[] args) throws Exception {
        DateTimeFormatter fmTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //创建线程池
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2,new ThreadPoolExecutor.AbortPolicy()){
            //根据需要重写方法
        };
        //没有返回值的任务
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                LocalDateTime now = LocalDateTime.now();
                System.out.println(now.format(fmTime) + " Runnable开始执行");
            }
        });
        //schedule(Runnable command, long delay, TimeUnit unit)
        //延迟2秒执行,没有返回值
        LocalDateTime now1 = LocalDateTime.now();
        System.out.println(now1.format(fmTime) + " 将Runnable延迟任务加入线程池,一秒后开始执行");
        executor.schedule(thread,2, TimeUnit.SECONDS);
    }
}

执行结果

2020-07-09 14:48:16 将Runnable延迟任务加入线程池,一秒后开始执行
2020-07-09 14:48:18 Runnable开始执行
  • schedule(Callable<V> callable, long delay, TimeUnit unit)
    执行有返回值的Callable任务
package com.sy.thread.example;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;

/**
 * Description: thread
 *
 * @author songyu
 */
public class ScheduledThreadPoolExecutorTest2 {
    public static void main(String[] args) throws Exception {
        DateTimeFormatter fmTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //创建线程池,、
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2,new ThreadPoolExecutor.AbortPolicy()){
            //根据需要重写方法
        };

        //有返回值的任务
        Callable callable = new Callable() {
            @Override
            public Object call() throws Exception {
                LocalDateTime now = LocalDateTime.now();
                System.out.println(now.format(fmTime) + " Callable开始执行");
                return "hello world";
            }
        };

        //schedule(Callable<V> callable, long delay, TimeUnit unit)
        //延迟五秒执行 有返回值
        LocalDateTime now2 = LocalDateTime.now();
        System.out.println(now2.format(fmTime) + " 将Callable延迟任务加入线程池,一秒后开始执行");
        Future future = executor.schedule(callable,5, TimeUnit.SECONDS);
        System.out.println("Callable任务返回内容为:" + future.get());
    }
}

执行结果

2020-07-09 14:54:49 将Callable延迟任务加入线程池,一秒后开始执行
2020-07-09 14:54:54 Callable开始执行
Callable任务返回内容为:hello world
  • scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
    执行周期性定时任务
    command: 任务
    initialDelay:初次执行的延迟时间
    period: 执行周期时间
    第一次是initialDelay后执行,第二次是initialDelay + period后执行,第三次是 initialDelay + period * 2,以此类推
package com.sy.thread.example;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Description: thread
 *
 * @author songyu
 */
public class ScheduledThreadPoolExecutorTest3 {
    public static void main(String[] args) {
        DateTimeFormatter fmTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //创建线程池
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2){
            //根据需要重写方法
        };

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                LocalDateTime now = LocalDateTime.now();
                System.out.println(now.format(fmTime) + " Runnabled周期任务开始执行");
            }
        });
        //scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
        //initialDelay 第一次延迟执行时间
        //period 周期时间
        //将任务提交到线程池,5秒后执行第一次任务,然后每隔10s执行一次
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now.format(fmTime) + " 将Runnable周期任务加入线程池,一秒后开始执行");
        executor.scheduleAtFixedRate(thread,5,10, TimeUnit.SECONDS);
    }
}

执行结果

2020-07-09 15:05:17 将Runnable周期任务加入线程池,一秒后开始执行
2020-07-09 15:05:22 Runnabled周期任务开始执行
2020-07-09 15:05:32 Runnabled周期任务开始执行
2020-07-09 15:05:42 Runnabled周期任务开始执行
2020-07-09 15:05:52 Runnabled周期任务开始执行
2020-07-09 15:06:02 Runnabled周期任务开始执行
2020-07-09 15:06:12 Runnabled周期任务开始执行
2020-07-09 15:06:22 Runnabled周期任务开始执行
2020-07-09 15:06:32 Runnabled周期任务开始执行
......
  • scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
    执行周期性定时任务
    command: 任务
    initialDelay:初次执行的延迟时间
    period: 执行周期时间
    第一次是initialDelay后执行,第二次是在第一次任务执行完成后开始算,period后执行,第三次是在第二次任务执行完成后开始算,period后执行,以此类推
package com.sy.thread.example;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Description: thread
 *
 * @author songyu
 */
public class ScheduledThreadPoolExecutorTest4 {
    public static void main(String[] args) {
        DateTimeFormatter fmTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //创建线程池
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2){
            //根据需要重写方法
        };

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    LocalDateTime now = LocalDateTime.now();
                    System.out.println(now.format(fmTime) + " Runnabled周期任务开始执行");
                    Random random = new Random();
                    int randomNumber1 = random.nextInt(10) * 1000;
                    System.out.println("阻塞" + randomNumber1 + "毫秒");
                    Thread.sleep(randomNumber1);
                    LocalDateTime now2 = LocalDateTime.now();
                    System.out.println(now2.format(fmTime) + " Runnabled周期任务执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
        //initialDelay 第一次延迟执行时间
        //period 周期时间
        //将任务提交到线程池,5秒后执行第一次任务,第一次执行完成后,10秒后执行下一次,除了第一次执行,后续的执行都是从上一个任务完成后开始算,period时间后执行
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now.format(fmTime) + " 将Runnable周期任务加入线程池,一秒后开始执行");
        executor.scheduleWithFixedDelay(thread,5,10, TimeUnit.SECONDS);
    }
}

执行结果

2020-07-09 15:26:04 将Runnable周期任务加入线程池,一秒后开始执行
2020-07-09 15:26:09 Runnabled周期任务开始执行
阻塞8000毫秒
2020-07-09 15:26:17 Runnabled周期任务执行结束
2020-07-09 15:26:27 Runnabled周期任务开始执行
阻塞3000毫秒
2020-07-09 15:26:30 Runnabled周期任务执行结束
2020-07-09 15:26:40 Runnabled周期任务开始执行
阻塞8000毫秒
2020-07-09 15:26:48 Runnabled周期任务执行结束
2020-07-09 15:26:58 Runnabled周期任务开始执行
阻塞9000毫秒
2020-07-09 15:27:07 Runnabled周期任务执行结束
2020-07-09 15:27:17 Runnabled周期任务开始执行
阻塞1000毫秒
2020-07-09 15:27:18 Runnabled周期任务执行结束
2020-07-09 15:27:28 Runnabled周期任务开始执行
......

ScheduledThreadPoolExecutor的execute()和submit()

execute() > schedule(Runnable command, long delay, TimeUnit unit)
submit() > schedule(Callable<V> callable, long delay, TimeUnit unit)

public void execute(Runnable command) {
  schedule(command, 0, NANOSECONDS);
}

public Future<?> submit(Runnable task) {
  return schedule(task, 0, NANOSECONDS);
}

上面几个简单的例子把ScheduledThreadPoolExecutor几种任务执行的方式都简单的实现了一下,自己可以扩展一下,然后把剩余的方法和学习一下。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342