Java并发编程之线程池

1、简介

Executor

接口。该接口提供了一种将任务提交与每个任务的运行机制分离的方法,包括线程使用、调度等细节。通常使用执行器,而不是显式创建线程。
例如:创建线程 new Thread(new(RunnableTask())).start()
更改:

Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());

Executors

线程池工具类,相当于一个工厂类,用来创建合适的线程池,返回ExecutorService(继承Executor)类型的线程池

ExecutorService newFixedThreadPool() : 创建固定大小的线程池
ExecutorService newSingleThreadExecutor() : 创建单个线程池。 线程池中只有一个线程
ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务
ScheduledExecutorService newSingleThreadScheduledExecutor() : 创建单个可以延迟或定时的执行任务线程池

ExecutorService

ExecutorService为线程池接口,提供了线程池生命周期方法,继承自Executor接口。
Shutdown方法将允许在终止之前执行以前提交的任务,而Shutdownow方法将阻止等待的任务启动,并尝试停止当前正在执行的任务。终止后,执行者没有正在执行的任务,没有等待执行的任务,也不能提交新任务。应关闭未使用的ExecutorService,以便回收其资源。
方法invokeAny和invokeAll执行最常用的批量执行形式,执行一组任务,然后等待至少一个或全部任务完成。

ThreadPoolExecutor

ExecutorService的实现类,是线程池的真正实现,他通过构造方法的一系列参数,来构成不同配置的线程池。

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime, TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

corePoolSize:核心线程数,默认情况下核心线程会一直存活,即使处于闲置状态也不会受keepAliveTime限制。除非将allowCoreThreadTimeOut设置为true。
maximumPoolSize:线程池所能容纳的最大线程数。超过这个数的线程将被阻塞。当任务队列为没有设置大小的LinkedBlockingDeque时,这个值无效。
keepAliveTime:非核心线程的闲置超时时间,超过这个时间就会被回收。
unit:指定keepAliveTime的单位,如TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时对corePoolSize生效。
workQueue:线程池中的任务队列.常用的有三种队列,SynchronousQueue,LinkedBlockingQueue,ArrayBlockingQueue。
threadFactory:线程工厂,提供创建新线程的功能。ThreadFactory是一个接口,只有一个方法interface()               
handler:策略,RejectedExecutionHandler也是一个接口,只有一个方法rejectedExecution()
当线程池中的资源已经全部使用,添加新线程被拒绝时,会调用RejectedExecutionHandler的rejectedExecution方法。
四种可选策略
# AbortPolicy(中止策略):直接抛出java.util.concurrent.RejectedExecutionException异常
# CallerRunsPolicy(呼叫方运行策略):若已达到待处理队列长度,将由主线程直接处理请求
# DiscardOldestPolicy(放弃最古老的政策):抛弃旧的任务;会导致被丢弃的任务无法再次被执行
# DiscardPolicy(放弃政策):抛弃当前任务;会导致被丢弃的任务无法再次被执行

线程池、new Thread

a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。

相比new Thread,线程池的好处在于:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。

2、线程的类型

固定线程池

Executors.newFixedThreadPool

	/**
	 * 创建一个线程池,该线程池重用在共享无边界队列上运行的固定数量的线程,在需要时使用提供的ThreadFactory创建新线程。
	 * 在任何时候,线程最多都是活动的处理任务。如果在所有线程都处于活动状态时提交其他任务,它们将在队列中等待,直到有线程可用。如果任何线程在关机前的执行过程中由于故障而终止,那么如果需要执行后续任务,将有一个新线程替代它。
	 * 池中的线程将一直存在,直到显式关闭。
	 */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, 
        							  nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

	//defaultHandler:new AbortPolicy()
	public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
    public static void main(String[] args) {
        fixedThreadPool();
    }

	public static void fixedThreadPool() {
        // 创建固定大小的线程池,线程数3
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3, new ThreadFactory() {
            int i = 0;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "fixed-" + i++);
            }
        });

        for (int i = 0; i < 10; i++) {
            fixedThreadPool.execute(() -> {
                try {
                    Thread.sleep(100);
                    log.info("固定线程池");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

在这里插入图片描述

单一线程池

Executors.newSingleThreadExecutor

	/**
	 * 创建一个执行器,该执行器使用一个工作线程在无界队列中运行,并在需要时使用提供的ThreadFactory创建一个新线程。
	 * 与其他等效的newFixedThreadPool(1,threadFactory)不同,返回的执行器保证不可重新配置以使用其他线程
	*/
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }
    public static void singleThreadExecutor() {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
            int i = 0;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "single-" + i++);
            }
        });

        for (int i = 0; i < 10; i++) {
            singleThreadExecutor.execute(() -> {
                try {
                    Thread.sleep(100);
                    log.info("单一线程池");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

在这里插入图片描述

缓存线程池

Executors.newCachedThreadPool

	/**
	 * 创建一个线程池,该线程池根据需要创建新线程,但在以前构建的线程可用时将重用这些线程,并在需要时使用提供的ThreadFactory创建新线程。
	 */
	public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }
    public static void cachedThreadPool() throws InterruptedException {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool(new ThreadFactory() {
            int i = 0;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "cached-" + i++);
            }
        });

        for (int i = 0; i < 10; i++) {
            cachedThreadPool.execute(() -> {
                try {
                    Thread.sleep(100);
                    log.info("缓存线程池");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        Thread.sleep(5000);

        for (int i = 0; i < 20; i++) {
            cachedThreadPool.execute(() -> {
                try {
                    Thread.sleep(100);
                    log.info("缓存线程池");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }

在这里插入图片描述

周期性线程池

Executors.newScheduledThreadPool

	/**
	 * 创建一个线程池,该线程池可以安排命令在给定延迟后运行,或定期执行
	 */
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }

    public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

	//ScheduledThreadPoolExecutor的父类是ThreadPoolExecutor
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
    public static void scheduledThreadPool() {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5, new ThreadFactory() {
            int i = 0;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "scheduled-" + i++);
            }
        });

        log.info("周期线程池,调用前");
        scheduledThreadPoolA(scheduledThreadPool);
//        scheduledThreadPoolB(scheduledThreadPool);
//        scheduledThreadPoolC(scheduledThreadPool);
    }

    private static void scheduledThreadPoolA(ScheduledExecutorService scheduledThreadPool) {
        for (int i = 0; i < 10; i++) {
            scheduledThreadPool.schedule(() -> {
                try {
                    Thread.sleep(100);
                    log.info("周期线程池,调用时延迟5秒执行一次任务,只执行一次");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, 5, TimeUnit.SECONDS);
        }
    }

    private static void scheduledThreadPoolB(ScheduledExecutorService scheduledThreadPool) {
        for (int i = 0; i < 10; i++) {
            scheduledThreadPool.scheduleAtFixedRate(() -> {
                try {
                    Thread.sleep(1000);
                    log.info("周期线程池,调用时延迟5秒执行一次任务,之后立即计算每过10秒再次执行一次,会不停重复执行,不受任务耗时影响,时间间隔固定");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, 5, 10, TimeUnit.SECONDS);
        }
    }

    private static void scheduledThreadPoolC(ScheduledExecutorService scheduledThreadPool) {
        for (int i = 0; i < 10; i++) {
            scheduledThreadPool.scheduleWithFixedDelay(() -> {
                try {
                    Thread.sleep(1000);
                    log.info("周期线程池,调用时延迟5秒执行一次任务,任务执行完毕之后才开始计算第10秒再次执行一次,会不停重复执行,受任务耗时影响,时间间隔不固定");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, 5, 10, TimeUnit.SECONDS);
        }
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

单一周期线程池

Executors.newSingleThreadScheduledExecutor

	/**
	 * 创建一个单线程执行器,该执行器可以安排命令在给定延迟后运行,或定期执行。
	 * 但是请注意,如果此单线程在关机前的执行过程中由于故障而终止,那么如果需要执行后续任务,将使用一个新线程代替它。
	 * 任务保证按顺序执行,并且在任何给定时间都不会有多个任务处于活动状态。
	 * 与其他等效的newScheduledThreadPool(1,threadFactory)不同,返回的执行器保证不可重新配置以使用其他线程。
	 */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

	public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }
    public static void singleThreadScheduledExecutor() {
        ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            int i = 0;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "single-sch-" + i++);
            }
        });

        log.info("单一周期线程池,调用前");
        for (int i = 0; i < 10; i++) {
            singleThreadScheduledExecutor.schedule(() -> {
                try {
                    Thread.sleep(1000);
                    log.info("单一周期线程池,调用时延迟5秒执行一次任务,只执行一次");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, 5, TimeUnit.SECONDS);
        }
    }

在这里插入图片描述

3、工作队列

线程池的规则

如果当前运行的线程数小于corePoolSize,有空闲的核心线程,则用空闲的线程来执行任务,没有就创建新线程(核心线程)来执行任务。
如果当前运行的线程数大于或等于corePoolSize,那么就把任务加入等待队列。
如果等待队列已满,那么创建新线程(非核心线程)来执行该任务。
如果创建新线程时导致当前运行的线程数超过maximumPoolSize,就根据饱和策略来拒绝该任务

SynchronousQueue队列

    private static final AtomicInteger ai = new AtomicInteger(1);
    private static final AtomicInteger ai2 = new AtomicInteger(1);

    public static void WorkQueue() throws InterruptedException {
        threadPoolExecutorA();
//        threadPoolExecutorB();
//        threadPoolExecutorC();
    }

    /**
     * 核心3,最大6,超时10秒,SynchronousQueue队列无长度
     * 当前运行线程数<=核心数,直接使用核心数
     * 当前运行线程数>核心数,不会加入任务队列,而是创建非核心线程来执行任务
     * 当前运行线程数>最大数,进行饱和策略(目前策略是直接丢弃)
     * 空闲非核心数,超过空闲时间时移除
     */
    public static void threadPoolExecutorA() throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutorA = new ThreadPoolExecutor(
                3,
                6,
                10, TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                new ThreadFactory() {
                    int i = 0;

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "threadA-" + i++);
                    }
                },
                new ThreadPoolExecutor.DiscardPolicy());

        System.out.println("先开三个线程");
        start(threadPoolExecutorA);
        System.out.println("=========================================");
        System.out.println("再开三个线程");
        start(threadPoolExecutorA);
        System.out.println("=========================================");
        System.out.println("再开三个线程");
        start(threadPoolExecutorA);
        System.out.println("=========================================");
        System.out.println("20秒后再开三个线程");
        Thread.sleep(20000);
        start(threadPoolExecutorA);
    }

	private static void start(ThreadPoolExecutor threadPoolExecutor) {
        for (int i = 1; i <= 3; i++) {
            log.info("创建线程总数:" + ai.getAndIncrement());
            threadPoolExecutor.execute(() -> {
                try {
                    Thread.sleep(3000);
                    log.info("执行线程数:" + ai2.getAndIncrement());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        System.out.println("核心线程数:" + threadPoolExecutor.getCorePoolSize());
        System.out.println("线程池数:" + threadPoolExecutor.getPoolSize());
        System.out.println("队列任务数:" + threadPoolExecutor.getQueue().size());
    }

在这里插入图片描述

ArrayBlockingQueue队列

    /**
     * 核心3,最大6,超时10秒,ArrayBlockingQueue队列长度5
     * 当前运行线程数<=核心数,直接使用核心数
     * 当前运行线程数>核心数,加入任务队列
     * 当前运行线程数>任务队列长度,创建非核心数(核心+非核心<=最大数)
     * 当前运行线程数>最大数,进行饱和策略(目前策略是直接丢弃)
     * 空闲非核心数,超过空闲时间时移除
     */
    public static void threadPoolExecutorB() throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutorB = new ThreadPoolExecutor(
                3,
                6,
                10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5),
                new ThreadFactory() {
                    int i = 0;

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "threadB-" + i++);
                    }
                },
                new ThreadPoolExecutor.DiscardPolicy());

        System.out.println("先开三个线程");
        start(threadPoolExecutorB);
        System.out.println("=========================================");
        System.out.println("再开三个线程");
        start(threadPoolExecutorB);
        System.out.println("=========================================");
        System.out.println("再开三个线程");
        start(threadPoolExecutorB);
        System.out.println("=========================================");
        System.out.println("20秒后再开三个线程");
        Thread.sleep(20000);
        start(threadPoolExecutorB);
    }

在这里插入图片描述

LinkedBlockingDeque队列

    /**
     * 核心3,最大6,超时10秒,LinkedBlockingDeque队列长度5
     * 当前运行线程数<=核心数,直接使用核心数
     * 当前运行线程数>核心数,加入任务队列
     * 当前运行线程数>任务队列长度,创建非核心数(核心+非核心<=最大数)
     * 当前运行线程数>最大数,进行饱和策略(目前策略是直接丢弃)
     * 空闲非核心数,超过空闲时间时移除
     */
    public static void threadPoolExecutorC() throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutorC = new ThreadPoolExecutor(
                3,
                6,
                10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(5),
                new ThreadFactory() {
                    int i = 0;

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "threadC-" + i++);
                    }
                },
                new ThreadPoolExecutor.DiscardPolicy());

        System.out.println("先开三个线程");
        start(threadPoolExecutorC);
        System.out.println("=========================================");
        System.out.println("再开三个线程");
        start(threadPoolExecutorC);
        System.out.println("=========================================");
        System.out.println("再开三个线程");
        start(threadPoolExecutorC);
        System.out.println("=========================================");
        System.out.println("20秒后再开三个线程");
        Thread.sleep(20000);
        start(threadPoolExecutorC);
    }

链表队列的执行效果跟数组队列是一样的
在这里插入图片描述

队列比较

队列是否有界是否缓冲锁个数并发性能
SynchronousQueue(同步队列)1线程少 (<20) ,Queue长度短 (<30) , 使用SynchronousQueue表现很稳定,而且在20个线程之内不管Queue长短,SynchronousQueue性能表现是最好的, SynchronousQueue跟Queue长短没有关系)
ArrayBlockingQueue(数组阻塞队列)1一般不用,并且在插入和删除元素时会产生额外的对象(跟LinkedBlockingQueue区别是必须指定大小)
LinkedBlockingQueue(链接阻塞队列)2(生产者锁和消费者锁)LinkedBlockingQueue性能表现远超ArrayBlockingQueue,不管线程多少,不管Queue长短,LinkedBlockingQueue都胜过ArrayBlockingQueue,线程多(>20),Queue长度长(>30),使用LinkedBlockingQueue(当LinkedBlockingQueue没指定大小是,最大线程数无效)

4、ThreadPoolTaskExecutor

在这里插入图片描述
ThreadPoolExecutor是一个java类不提供spring生命周期和参数装配
在这里插入图片描述
ThreadPoolTaskExecutor实现了InitializingBean, DisposableBean ,xxaware等,具有spring特性。
相比较于ThreadPoolExecutor:
1、ThreadPoolTaskExecutor底层使用ThreadPoolExecutor构造线程池并进行增强,扩展了更多特性
2、ThreadPoolTaskExecutor只关注自己增强的部分,任务执行还是ThreadPoolExecutor处理。
3、ThreadPoolTaskExecutor使用@Bean注入,容器关闭会自动调用其实现InitializingBean接口的关闭方法。

    /**
     * 配置:ThreadPoolTaskExecutor
     */
    @Bean(name = "threadPoolTaskExecutor", destroyMethod = "shutdown")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置线程池前缀:方便排查
        executor.setThreadNamePrefix("thread-task-");
        // 设置线程池的核心线程数量
        executor.setCorePoolSize(10);
        // 设置线程池的最大值
        executor.setMaxPoolSize(15);
        // 设置线程池的队列大小
        executor.setQueueCapacity(250);
        // 设置线程最大空闲时间,单位:秒(非核心线程数)
        executor.setKeepAliveSeconds(3000);
        // 饱和策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        // 实现了InitializingBean接口,可不需要执行这一初始化步骤
        // executor.initialize();
        return executor;
    }

@Slf4j
@Component
@EnableScheduling
public class ExecutorTestService {

    @Scheduled(fixedRate = 60 * 60 * 1000)
    public void fixedRate() throws Exception {
        threadPoolTaskExecutor();
    }

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    public void threadPoolTaskExecutor() {
        for (int i = 0; i < 20; i++) {
            taskExecutor.execute(() -> {
                try {
                    Thread.sleep(2000);
                    log.info("ThreadPoolTaskExecutor 的 execute 方法调用");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}    

在这里插入图片描述

5、ScheduledThreadPoolExecutor

在这里插入图片描述
一个可以额外安排命令在给定延迟后运行,或定期执行的ThreadPoolExecutor。

    /**
     * 配置:ScheduledThreadPoolExecutor
     */
    @Bean(name = "scheduledPoolTaskExecutor", destroyMethod = "shutdown")
    public ScheduledThreadPoolExecutor scheduledThreadPoolExecutor() {
        // 第一个参数:核心线程数
        // 第二个参数:线程工厂(此处用来设置线程名)
        // 第三次参数:饱和策略
        // 饱和策略
        return new ScheduledThreadPoolExecutor(10,
                new ThreadFactory() {
                    int i = 0;

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "scheduled-" + i++);
                    }
                },
                new ThreadPoolExecutor.DiscardPolicy()
        );
    }

	@Resource(name = "scheduledPoolTaskExecutor")
    private ScheduledThreadPoolExecutor scheduled;

    public void scheduledPoolTaskExecutor() throws Exception {
        scheduleA();
    }

    public void scheduleA() throws ExecutionException, InterruptedException {
        scheduled.execute(new Runnable() {
            @Override
            public void run() {
                log.info("execute ");
            }
        });

        Thread.sleep(2000);
        scheduled.submit(new Runnable() {
            @Override
            public void run() {
                log.info("submit 无返回值");
            }
        });

        Thread.sleep(2000);
        Future<String> result = scheduled.submit(new Runnable() {
            @Override
            public void run() {
                log.info("submit 有返回值");
            }
        }, "ok");
        System.out.println("result = " + result.get());

        Thread.sleep(2000);
        Future<String> submit = scheduled.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("submit 有返回值");
                return "ok";
            }
        });
        System.out.println("submit = " + submit.get());
    }

在这里插入图片描述

    public void scheduleB() throws ExecutionException, InterruptedException {
        scheduled.schedule(new Runnable() {
            @Override
            public void run() {
                log.info("方法调用,延迟5秒执行一次, 只执行一次");
            }
        }, 5000, TimeUnit.MILLISECONDS);

        ScheduledFuture<String> result = scheduled.schedule(new Callable<String>() {
            @Override
            public String call() {
                log.info("方法调用,延迟10秒执行一次, 只执行一次");
                return "ok";
            }
        }, 10000, TimeUnit.MILLISECONDS);
        System.out.println("result = " + result.get());
    }

    public void scheduleC() {
        scheduled.scheduleAtFixedRate(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                log.info("方法调用,延迟5秒首次执行,之后每过3秒轮询, 不受run方法执行耗时影响");
                Thread.sleep(2000);
            }
        }, 5000, 3000, TimeUnit.MILLISECONDS);
    }

    public void scheduleD() {
        scheduled.scheduleWithFixedDelay(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                log.info("方法调用,延迟5秒首次执行,之后每过3秒轮询,受run方法执行耗时影响");
                Thread.sleep(2000);
            }
        }, 5000, 3000, TimeUnit.MILLISECONDS);
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值