ScheduledExecutorService

ExecutorService的子接口,具备了延迟运行或定期执行任务的能力。

1、常用获取方式 

注:还是通过 Executors. 的方式进行调用

1)static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 

 ——  创建一个可重用固定线程数的线程池且允许延迟运行或(重复/)定期执行任务

static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)          

—— 创建一个可重用固定线程数的线程池,且线程池中的所有线程都使用ThreadFactory来创建,且允许延迟运行或定期执行任务

2)static ScheduledExecutorService newSingleThreadScheduledExecutor()          

—— 创建一个单线程执行程序,它允许在给定延迟后运行命令或者(重复/)定期地执行任务

static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)            

—— 创建一个单线程执行程序,且线程池中的所有线程都使用ThreadFactory来创建,且允许在给定延迟后运行命令或者定期地执行任务

2、常用方法

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

—— 延迟时间单位是unit,数量是delay的时间后执行callable

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

—— 延迟时间单位是unit,数量是delay的时间后执行command   

下面的方法可以重复执行任务:(两种间隔方式)

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

 ——  延迟时间单位是unit,数量是initialDelay的时间后,每间隔period时间重复执行一次command

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

—— 创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟(即:同上面一样,也是重复执行,但是,延迟时间是从第一次(仅仅是第一次?还是每次?:每一次)重复/执行完后的时间开始算起的

示意图:

上面是scheduleAtFixedRate(...),下面是scheduleWithFixedDelay(...)

spring请求线程_延迟执行

 3、代码示例

(1)最简单的延迟执行(一个或多个任务)

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

package com.zhoulz.demo03;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 测试ScheduledExecutorService接口中延迟执行任务和重复执行任务的功能
 */
public class ScheduledExecutorServiceDemo01 {
    public static void main(String[] args) {
        // 1、获取一个具备延迟执行任务的线程池对象
        ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
        // 2、创建多个任务对象,提交任务,每个任务延迟2秒执行
        // (同样,这个任务可以单独创建一个类,也可以通过匿名内部类的方式)
        // 提交任务用方法,而不是submit()方法了

        // 下面先提交一个任务
        //es.schedule(new MyRunnable(666),2, TimeUnit.SECONDS);
        // 提交多个任务—— 通过for循环
        for (int i = 1; i <= 10; i++) {
            es.schedule(new MyRunnable(i),2, TimeUnit.SECONDS);
        }

        // 下面这个打印是在main方法中的,不会延迟。
        // 所以,正常情况是:打印“over”后,延迟2秒后执行任务
        System.out.println("over");
    }
}

class MyRunnable implements Runnable{
    private int id;

    public MyRunnable(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + "执行了任务:" + id);
    }
}

结果:

spring请求线程_开发语言_02

(2)只执行一个任务,但是使其重复执行

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

package com.zhoulz.demo03;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * 测试ScheduledExecutorService接口中延迟执行任务和重复执行任务的功能
 */
public class ScheduledExecutorServiceDemo02 {
    public static void main(String[] args) {
        // 1、获取一个具备延迟执行任务的线程池对象
        ScheduledExecutorService es = Executors.newScheduledThreadPool(3, new ThreadFactory() {
            int n = 1;
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,"自定义的线程名zlz:"+ n++);
            }
        });
        // 2、创建多个任务对象,提交任务,每个任务延迟2秒执行
        // (匿名内部类的方式,见上面)

        // 下面不再提交多个任务,而是就提交1个任务,并让其重复执行
        // 初识延迟1秒,间隔2秒
        es.scheduleAtFixedRate(new MyRunnable2(666),1,2,TimeUnit.SECONDS);

        // 提交多个任务—— 通过for循环
        /*for (int i = 1; i <= 10; i++) {
            es.schedule(new MyRunnable2(i),2, TimeUnit.SECONDS);
        }*/
        System.out.println("over");
    }
}

class MyRunnable2 implements Runnable{
    private int id;

    public MyRunnable2(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        // 模拟任务执行时间1.5秒,这个1.5秒是在间隔时间2秒钟之类的
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "执行了任务:" + id);
    }
}

结果:

spring请求线程_java_03

 (3)只执行一个任务,但是使其重复执行

区别于(2),所用的是scheduleWithFixedDelay()方法 —— 来提交任务

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

同时,获取线程的方式用的是:

(即单线程的,见下面,(2)用的是指定线程newScheduledThreadPool() 

static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)  -—— 且所有线程都使用ThreadFactory(线程工厂)来创建

package com.zhoulz.demo03;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * 测试ScheduledExecutorService接口中延迟执行任务和重复执行任务的功能
 */
public class ScheduledExecutorServiceDemo03 {
    public static void main(String[] args) {
        // 1、获取一个具备延迟执行任务的线程池对象
        ScheduledExecutorService es = Executors.newSingleThreadScheduledExecutor( new ThreadFactory() {
            int n = 1;
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,"自定义的线程名zlz:"+ n++);
            }
        });
        // 2、创建多个任务对象,提交任务,每个任务延迟2秒执行

        // 下面不再提交多个任务,而是就提交1个任务,并让其重复执行
        // 初识延迟1秒,间隔2秒
        es.scheduleWithFixedDelay(new MyRunnable3(666),1,2,TimeUnit.SECONDS);

        System.out.println("over");
    }
}

class MyRunnable3 implements Runnable{
    private int id;

    public MyRunnable3(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        // 模拟任务执行时间2秒,所以每间隔2+2=4秒后,才会有一次任务输出
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "执行了任务:" + id);
    }
}

结果:任务输出之间间隔了4秒。