Java并发编程-JDK线程池和Spring线程池(三)

1,383 阅读3分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

前言

前面线程池原理和线程池源码都是基于JDK线程池介绍的,Spring 线程池类似一个二方包对JDK线程池常用的一些操作进行了封装,便于业务代码中去使用, 很多同学开发的过程中很容易混淆。

线程池系列
Java并发编程-线程池(一)
Java并发编程-线程池源码分析(二)

1. JDK线程池

1.1 ThreadPoolExecutor 线程池实现类

image.png ThreadPoolExecutor 我们已经非常熟悉了, 通过构造函数创建线程池。阿里巴巴java开发手册建议是用这种方式创建。因为自己创建的线程池比较可控。核心线程数,阻塞队列和最大线程数大小等。

1.2 ScheduledThreadPoolExecutor 实现类

  • ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后执行任务,或者定期执行任务。通常使用工厂类Executors来创建。
  • ScheduledThreadPoolExecutor的功能与Timer类似,但比Timer更强大,更灵活,Timer对应的是单个后台线程,而ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。

1.3 Executors 工具类

Executors 创建线程工具类, 相当于一个工厂类,用来创建合适的线程池,返回ExecutorService类型的线程池。

1.3.1 newFixedThreadPool

创建一个固定大小的线程池, ThreadFactory是一个线程工厂, 用来创建线程, 如果不指定是用默认的线程工厂DefaultThreadFactory创建。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);
}

看完构造函数我们可以看出来,这里的固定大小线程是核心线程数和最大线程数大小, 但是没有设置阻塞队列的大小, 默认是Integer.MAX_VALUE

1.3.2 newSingleThreadExecutor

创建单个线程池。 线程池中只有一个线程


public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

1.3.3 newCachedThreadPool

缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}

1.3.4 newSingleThreadScheduledExecutor

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}

public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1, threadFactory));
}

1.3.5 newScheduledThreadPool

创建固定大小的线程,可以延迟或定时的执行任务.

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

2. Spring 线程池

2.1 ThreadPoolTaskExecutor

ThreadPoolTaskExecutor 是Spring提供的线程池。

2.1.1 ThreadPoolTaskExecutor框架

image.png 核心的属性其实也就是JDK线程池的一些属性,Spring是基于JDK线程池结合Spring管理做的一些二次封装。 一些核心的参数和方法可以看下官方文档的介绍。

image.png

2.1.2 ThreadPoolTaskExecutor 使用
@Configuration
public class ThreadPoolConfig {

    @Bean
    public ThreadPoolTaskExecutor createThreadPoolTaskExecutor () {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("xx定时任务");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        return executor;
    }
}
@SpringBootTest
public class ThreadPoolTest {

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Test
    public void test() {
        threadPoolTaskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程池测试");
            }
        });
    }
}
@SpringBootTest
public class ThreadPoolTest {

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Test
    public void test() {
        threadPoolTaskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程池测试1");
                System.out.println(Thread.currentThread().getName());
            }
        });

        threadPoolTaskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程池测试2");
                System.out.println(Thread.currentThread().getName());
            }
        });
    }
}

image.png

最后

我们可以思考一下几个问题

  1. JDK线程池和Spring线程池在我们平时项目中如何使用的?
  2. 我们平时架构设计中的线程隔离以及线程池优雅关闭和优雅停机时怎么做的?
  3. 当我们用异步线程池又是如何做到优雅停机和关闭的?

参考文档

《Spting官网:Class ThreadPoolTaskExecutor》
《阿里巴巴Java开发手册》
ThreadPoolTaskScheduler线程池的优雅关闭
如何优雅的使用和理解线程池