线程池分类以及7个参数,4种拒绝策略,5种运行状态

线程池的运行过程

Java并发篇—线程池入门扫盲指南

1:当一个任务提交时,如果CorePool中的核心线程少于CorePoolSize,则创建一个新线程执行任务(需要全局锁

2:如果CorePool中没有空闲的线程,那么加入BlockingQueue等待核心线程拉取任务执行

3:如果BlockingQueue已满,创建新线程后如果大于maximumPoolSize就跳转到4拒绝执行任务,如果小于就创建新线程执行任务(需要全局锁

4:四种不同的拒绝策略,通过rejectedExecution()方法执行。

需要获取全局锁导致线程池的性能大大下降,应该尽量避免产生步骤1和步骤3

 

使用Executors创建线程池 :但一般都不建议这么创建线程池

package pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * alibab开发手册以及工作中都是用 ThreadPoolExecutor 创建线程池,
 * 而不是用三大方法 newSingleThreadExecutor,newFixedThreadPool,newCachedThreadPool这三种
 */

public class Demo01 {
    public static void main(String[] args) {
        // 单个线程
        ExecutorService threadpool = Executors.newSingleThreadExecutor();
        
        // 固定线程池大小
        //ExecutorService threadpool = Executors.newFixedThreadPool(5);

        // 可伸缩的,遇强则强,遇弱则弱
        ExecutorService threadpool = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            threadpool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"  ok");
            });
        }
        threadpool.shutdown();

    }

}

 

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

 

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

 从源码中可以看出,newSingleThreadExecutor只允许创建单个线程,其他的线程都会被放在 LinkedBlockingQueue 阻塞队列中,而 newFixedThreadPool 能够创建自定义数量的线程数,同时,两种线程池都使用  LinkedBlockingQueue 阻塞队列,而阻塞队列的长度为 Integer.MAX_VALUE = 2147483647 ,过多的创建线程可能会造成内存溢出,也就是 OOM。

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

 而在 newCachedThreadPool 线程池中将最大的线程池数量设置为 Integer.MAX_VALUE ,过多的创建线程的话也会造成一个 内存溢出,OOM。所以阿里云开发手册明确指出不建议使用这三种方式创建线程池,而是采取了自定义七大参数的方式创建线程池。

七大参数的设置:

package pool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo02 {
    public static void main(String[] args) {
        // corePoolSize核心线程池,默认开启的线程池数量
        //  maximumPoolSize 最大线程池,
        //  keepAliveTime + TimeUnit.SECONDS 除核心线程池以外的3个线程池空闲时,保持 3 秒无别的线程后关闭
        //  ArrayBlockingQueue 阻塞队列候客区
        //  ThreadFactory线程工厂一般设为默认值不用改
        // 线程池 4 大策略之一 超过 maximumPoolSize + 阻塞队列=线程最大承载时触发
        //  1.AbortPolicy 报错 concurrent.RejectedExecutionException
        //  2.CallerRunsPolicy  哪来的去哪里,打发到 main 线程
        //  3.DiscardOldestPolicy 即使线程数超过最大承载,也不会抛出异常,丢掉任务
        //  4.DiscardPolicy 队列满了尝试会与最早的线程竞争,同时不会抛出异常

        //池的最大大小如何设置(maximumPoolSize)
        //1.cpu 密集型,电脑或者处理器是几核就设置为几,保持cpu效率最高====6核12线程(设为12动态获取)
        //2.IO 密集型 根据 十分占用 io 资源的任务数决定。一般设为 2倍 任务数
        System.out.println(Runtime.getRuntime().availableProcessors());
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                 2,
                 5,
                 3,
                 TimeUnit.SECONDS,
                 new ArrayBlockingQueue<>(3),
                 Executors.defaultThreadFactory(),
                 //new ThreadPoolExecutor.AbortPolicy()
                 //new ThreadPoolExecutor.CallerRunsPolicy()
                //new ThreadPoolExecutor.DiscardOldestPolicy()
                new ThreadPoolExecutor.DiscardPolicy()
        );

         // 线程最大承载: queue + max
        for (int i = 0; i < 9; i++) {
            threadPoolExecutor.execute(()->{
                System.out.println(Thread.currentThread().getName()+" ok");
            });
        }
        threadPoolExecutor.shutdown();
    }
}

corePoolSize核心线程池,默认开启的线程池数量
maximumPoolSize 最大线程池,
keepAliveTime + TimeUnit.SECONDS 除核心线程池以外的其他线程池空闲时,保持 3 秒(时间自己定义)无别的线程进来,3秒后关闭除核心线程池外的线程
ArrayBlockingQueue 阻塞队列候客区
ThreadFactory线程工厂一般设为默认值不用改

阻塞队列

阻塞队列-----四组api

 

四大策略

线程池 4 大策略, 超过 maximumPoolSize + 阻塞队列=线程最大承载时触发,线程数不达到最大承载时不会执行4个策略

以下是4个策略分别执行的操作
        1.AbortPolicy 报错 concurrent.RejectedExecutionException
        2.CallerRunsPolicy  哪来的去哪里,若为主线程,打发到 main 线程
        3.DiscardOldestPolicy 即使线程数超过最大承载,也不会抛出异常,丢掉任务
        4.DiscardPolicy 队列满了尝试会与最早的线程竞争,同时不会抛出异常

 

线程池的5种运行状态

 

Running状态下添加处理线程

Shutdown状态下不再接受新的线程,但仍会处理阻塞队列和线程池中的线程

Stop状态下会中断正在处理的线程,不处理阻塞队列和其他

Tidying状态下所有线程执行完毕,ctl记录的线程数为0

Terminated状态下线程池终止

 

最后简单介绍一下

池的最大大小如何设置(即maximumPoolSize参数的设置)
        1. CPU 密集型,电脑或者处理器是几核就设置为几,保持cpu效率最高====如我的电脑为6核12线程(设为12)

        动态获取:

Runtime.getRuntime().availableProcessors()


        2. IO 密集型 根据 十分占用 io 资源的任务数决定。一般设为 2倍 密集任务数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值