• 06-线程池(3大方法、7大参数,4种拒绝策略)


    池化技术

    程序运行的本质:占用系统的资源==》优化资源的使用==池化技术:提前准备好资源,如果需要使用,则到池里用,用完后释放返回给池里以备下次或其他线程使用。
    线程池、连接池、内存池、对象池、创建销毁都非常的浪费资源。
    优点

    1. 降低资源的消耗
    2. 提高响应的速度
    3. 方便管理
    4. 线程的复用,可以控制最大并发数,管理线程
    三大方法
    1单个线程池

    新建单个线程池

    
    /**
     * @author 
     * @Date 2022/7/26
     * @apiNote
     */
    public class TApi {
        public static void main(String[] args) {
            ExecutorService singlePool=Executors.newSingleThreadExecutor();
    
                try {
                    for (int i = 0; i < 100; i++) {
                    singlePool.execute(()->{//代替new Thread.start(),利用线程池执行线程
                        System.out.println(Thread.currentThread().getName()+"OK");
                    });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    singlePool.shutdown();//关闭线程池
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    结果:
    无论多少个线程处理,都在同一个线程池里面执行。
    在这里插入图片描述

    2固定线程池

    新建固定个数的线程池

    
    /**
     * @author
     * @Date 2022/7/26
     * @apiNote
     */
    public class TApi {
        public static void main(String[] args) {
        //新建5个线程池
            ExecutorService fixedPool=Executors.newFixedThreadPool(5);
    
                try {
                    for (int i = 0; i < 100; i++) {
                        fixedPool.execute(()->{
                        System.out.println(Thread.currentThread().getName()+"====OK");
                    });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    fixedPool.shutdown();//关闭线程池
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    结果:
    无论多少个线程执行,都在5个线程池当中。
    在这里插入图片描述

    3灵活线程池

    根据系统CPU大小,灵活创建线程池,CPU越好,创建线程池越多。

    
    /**
     * @author
     * @Date 2022/7/26
     * @apiNote
     */
    public class TApi {
        public static void main(String[] args) {
            ExecutorService cachedPool=Executors.newCachedThreadPool();
    
                try {
                    for (int i = 0; i < 100; i++) {
                        cachedPool.execute(()->{
                        System.out.println(Thread.currentThread().getName()+"====OK");
                    });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    cachedPool.shutdown();//关闭线程池
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    结果:
    我的电脑当前可以创建最多线程池30个。
    在这里插入图片描述

    7大参数

    源码:

    //单个线程池源码
        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 static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    //三个线程池的本质都是ThreadPoolExecutor
    以下为ThreadPoolExecutor源码

        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.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    线程池不允许使用Executor去创建,而是通过ThreadPoolExecutor的方式,这样是为了让我们更好的了解线程池的运行规则,规避资源耗尽的风险。
    Executor直接使用弊端为:

    1. FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,导致OOM,
    2. CachedThreadPool和SceduledThreadPool:允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量线程,导致OOM,

    示例:

    1. 当有两个线程进行时:
    
    /**
     * @author
     * @Date 2022/7/26
     * @apiNote
     */
    public class TApi {
        public static void main(String[] args) {
            ExecutorService threadPool =new ThreadPoolExecutor(2,
                    5,
                    3,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy()//线程池满了,阻塞队列满了,进入后不再处理并抛出异常
            );
    
                try {
                    for (int i = 1; i <= 2; i++) {
                        threadPool.execute(()->{
                        System.out.println(Thread.currentThread().getName()+"====OK");
                    });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    threadPool.shutdown();
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    结果:
    在这里插入图片描述
    分析:当前两个核心线程池在处理

    2.当有3个线程进行时

    
    /**
     * @author 
     * @Date 2022/7/26
     * @apiNote
     */
    public class TApi {
        public static void main(String[] args) {
            ExecutorService threadPool =new ThreadPoolExecutor(2,
                    5,
                    3,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy()//线程池满了,阻塞队列满了,进入后不再处理并抛出异常
            );
    
                try {
                    for (int i = 1; i <= 3; i++) {
                        threadPool.execute(()->{
                        System.out.println(Thread.currentThread().getName()+"====OK");
                    });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    threadPool.shutdown();
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    结果:
    在这里插入图片描述
    分析:当前两个核心线程池在处理

    3.四个线程:
    在这里插入图片描述
    两个核心线程池在处理

    4.五个线程:
    在这里插入图片描述
    5.六个线程:
    在这里插入图片描述
    两个核心线程池外加一个线程池在处理。

    6.八个线程
    在这里插入图片描述

    7.九个线程
    在这里插入图片描述
    当九个线程进行时,超过了设定最大线程池数量(5)+阻塞队列(3)个(8<9),触发拒绝策略abortPolicy,抛出异常。

    四种拒绝策略

    除去上面的AbortPolicy拒绝策略,以下还有三种:
    1.CallerRunPolicy拒绝策略
    含义:哪来的回哪去

    在这里插入图片描述
    结果:
    由主线程发出的,超过设定数量,会返回给主线程。
    在这里插入图片描述
    2.DiscardPolicy拒绝策略
    在这里插入图片描述
    结果:
    在这里插入图片描述
    达到设定线程池的数量8后,队列满后,之后第九个线程会被废弃掉,不抛出异常。

    3.DiscardOldestPolicy
    在这里插入图片描述
    结果:
    达到设定的最大线程数量8,第九个会尝试和第一个竞争,竞争成功会占用第一个,竞争失败就会自动丢弃掉。也不会抛出异常
    在这里插入图片描述
    最大线程如何定义

    1. CPU密集型:服务器几核CPU,就定义最大线程池数,如12核CPU就定义线程池数最大数量为12,可以保证CPU利用效率最高
    2. IO密集型:判断程序中十分消耗IO的程序,大于这个就可以
  • 相关阅读:
    算法通关村第三关-青铜挑战数组专题
    好书分享:《精装版|VirtualLab Fusion高速物理光学软件中文手册》
    centos安装redis教程
    [附源码]Python计算机毕业设计Django高校学生宿舍管理系统
    JAVA:SpringBoot中使用websocket出现404问题
    Java进阶(八)Stream、异常体系
    图像处理中几何畸变校正,图像纠正的方法有哪些
    百分点科技联合权威机构发布汽车安全市场表现报告
    【Rust日报】2022-07-05 让 Rust 库更优美的九个建议
    Mybatis学习|Mybatis缓存:一级缓存、二级缓存
  • 原文地址:https://blog.csdn.net/niannujiao6/article/details/125996006