springboot线程池的使用方式1

线程池的创建方法 总共有 7 种,但总体来说可分为 2 类:
  • 一类是通过 ThreadPoolExecutor 创建的线程池;
  • 另一个类是通过 Executors 创建的线程池。
1. Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
2. Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,当执行第二个任务时第一个任务已经完成,
    会复用执行第一个任务的线程,若线程数不够,则一直新建线程;
3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
4. Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
5. Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
6. Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定),创建一个具有并行级别的work-stealing线程池,
  【JDK 1.8 添加】可以传入线程的数量,不传入,则默认使用当前计算机中可用的cpu数量,能够合理的使用CPU进行对任务操作(并行操作),适合使用在很耗时的任务中。
7. ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置,后面会详细讲。
例如:
   ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 50, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000));
最大线程数:50: 排队队列最大数:1000
当线程池中正在使用的线程数达到了设置的最大的值(50),而且队列已(1000),还有数据进来的话就会报错。
即: 最大排队数 LinkedBlockingQueue要给一个总得要处理的预估数,比如处理100w的数据。
 
【推荐】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
3)也就是说如果执行的job很慢,就尽量不要使用上述2种线程池。相反的,如果处理很快的job,则可以使用。
 
参数 1:corePoolSize
核心线程数,线程池中始终存活的线程数。
参数 2:maximumPoolSize
最大线程数,线程池中允许的最大线程数,当线程池的任务队列满了之后可以创建的最大线程数。
参数 3:keepAliveTime
最大线程数可以存活的时间,当线程中没有任务执行时,最大线程就会销毁一部分,最终保持核心线程数量的线程。
参数 4:unit:
单位是和参数 3 存活时间配合使用的,合在一起用于设定线程的存活时间
参数 5:workQueue
一个阻塞队列,用来存储线程池等待执行的任务,均为线程安全,它包含以下 7 种类型:
  • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
  • LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
  • SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
  • PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
  • DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
  • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
较常用的是 LinkedBlockingQueue 和 Synchronous,线程池的排队策略使用场景:
ArrayBlockingQueue预先分配好一段连续内存,更稳定
LinkedBlockingQueue 读写锁分离,吞吐量更大
参数 6:ThreadFactory
线程工厂,主要用来创建线程,默认为正常优先级、非守护线程。
参数 7:RejectedExecutionHandler
拒绝策略,拒绝处理任务时的策略,系统提供了 4 种可选:
  • AbortPolicy:拒绝并抛出异常。
  • CallerRunsPolicy:使用当前调用的线程来执行此任务。
  • DiscardOldestPolicy:抛弃队列头部(最旧)的一个任务,并执行当前任务。
  • DiscardPolicy:忽略并抛弃当前任务。
默认策略为 AbortPolicy
/**
 * @Author Tim
 * @Date 2022/6/15 16:03
 */
@Service
public class MultiThreadServiceImpl {
    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 1.处理速度一般,并且是从回收的线程池中拿出原来的线程复用的.
     *   如果执行的job很慢,就尽量不要使用这种线程池。相反的,如果job处理很快,则可以使用。
     */
    private static final ExecutorService executorService = Executors.newCachedThreadPool(new BasicThreadFactory.Builder()
        .namingPattern("create-card-thread-%d").build());

    /**
     * 2.处理速度较快,创建一个具有并行级别的work-stealing线程池。 parallelism: 并发级别,适合使用在很耗时的任务中
     */
    private static final ExecutorService newWorkStealingPool = Executors.newWorkStealingPool();

    /**
     * 3.处理速度较快,核心线程数:10, 最大活跃数:50, 最大线程数可以存活的时间:60s,  用来存储线程池等待执行的任务数:100w
     * 在不配置RejectedExecutionHandler的情况下,如果实际处理数100w超过了设置队列等待数Queue,会抛异常。
     */
    private static final ThreadPoolExecutor threadPoolLocal =
        new ThreadPoolExecutor(10, 20, 20, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(1000000));

    /**
     * 3. 参数不同。
     * 配置RejectedExecutionHandler的情况下,不会报错,CallerRunsPolicy:使用当前调用的线程来执行此任务。
     */
    private ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 20, TimeUnit.SECONDS,
        new ArrayBlockingQueue(20, true), new ThreadPoolExecutor.CallerRunsPolicy());


    public void insertUsersByThreads() {
        for (int i = 0; i < 1000000; i++) {
            //第二种
//            CompletableFuture.runAsync(() -> {
//                UserInfoPO userInfoPO = new UserInfoPO();
//                userInfoPO.setUserEmail("testEmail");
//                userInfoPO.setUserName(RandomStringUtils.randomNumeric(4));
//                userInfoPO.setUserId(RandomStringUtils.randomNumeric(4));
//                userInfoPO.setUserSex("boy");
//                System.out.println("userInfoPO....." + userInfoPO.toString());
//                userInfoMapper.insert(userInfoPO);
//            }, newWorkStealingPool);
            //第三种
            newWorkStealingPool.execute(() ->{
                UserInfoPO userInfoPO = new UserInfoPO();
                userInfoPO.setUserEmail("testEmail");
                userInfoPO.setUserId(RandomStringUtils.randomNumeric(8));
                userInfoPO.setUserName(RandomStringUtils.randomNumeric(8));
                userInfoPO.setUserSex("boy");
                System.out.println("userInfoPO....." + userInfoPO.toString());
                userInfoMapper.insert(userInfoPO);
            });
            //第一种
//            CompletableFuture.runAsync(() -> {
//                UserInfoPO userInfoPO = new UserInfoPO();
//                userInfoPO.setUserEmail("testEmail");
//                userInfoPO.setUserName(RandomStringUtils.randomNumeric(4));
//                userInfoPO.setUserId(RandomStringUtils.randomNumeric(4));
//                userInfoPO.setUserSex("boy");
//                System.out.println("userInfoPO....." + userInfoPO.toString());
//                userInfoMapper.insert(userInfoPO);
//            }, executorService);

        }
    }
posted @ 2022-11-15 10:29  威兰达  阅读(1396)  评论(0编辑  收藏  举报