JUC(7):线程池(重点)3大方法、7大策略、4中拒绝策略

池化技术

程序运行的本质:程序一旦运行,就会占用系统资源!优化资源的使用!

什么是池化技术

池化技术 (Pool) 是一种很常见的编程技巧,在请求量大时能明显优化应用性能,降低系统频繁建连的资源开销。我们日常工作中常见的有数据库连接池、线程池、对象池等,它们的特点都是将 “昂贵的”、“费时的” 的资源维护在一个特定的 “池子” 中,规定其最小连接数、最大连接数、阻塞队列等配置,方便进行统一管理和复用,通常还会附带一些探活机制、强制回收、监控一类的配套功能。

线程池的好处

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

线程池:三大方法、7大参数、4种拒绝策略

三大方法(Executors)

ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线// ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一
个固定的线程池的大小
// ExecutorService threadPool = Executors.newCachedThreadPool(); // 可伸缩
的,遇强则强,遇弱则弱

需要注意两点

  1. 在使用线程池之后,我们应该使用线程池来创建线程,而不是之前的new Thread去创建
  2. 线程池用完,程序结束时,关闭线程池
 try {
            for (int i = 0; i <10 ; i++) {
                //使用线程池之后,使用线程池来创建线程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束时,关闭线程池
            threadPool.shutdown();
        }
    }

7大参数

首先分析一下上面三个方法的底层
单个线程
在这里插入图片描述
创建一个固定的线程池的大小

在这里插入图片描述
可伸缩的,遇强则强,遇弱则弱
在这里插入图片描述
通过上面上个底层代码我们可以知道本质上调用的都是:ThreadPoolExecutor
通过进入他的底层,在通过this可以看到下面的底层代码!在这里面我们就可以看到7大参数!
在这里插入图片描述
7大参数的意义如下:

int corePoolSize, // 核心线程池大小                         
int maximumPoolSize, // 线程池最大容量                      
long keepAliveTime, // 超时了没有人调用就会释放                          
TimeUnit unit, // 超时单位                         
BlockingQueue<Runnable> workQueue, // 阻塞队列                          
ThreadFactory threadFactory, // 线程工厂:创建线程的,一般不用动                          
RejectedExecutionHandler handle // 拒绝策略) 

四种拒绝策略(线程池饱和策略)

在这里插入图片描述

  • (默认的)new ThreadPoolExecutor.AbortPolicy() // 队列满了,还有人进来,不处理这个人的,抛出异常
  • new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!
  • new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
  • new ThreadPoolExecutor.DiscardOldestPolicy() //当任务被拒绝添加时,会抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。在rejectedExecution先从任务队列中弹出最先加入的任务,空出一个位置,然后再次执行execute方法把任务加入队列。即将最早进入队列的任务删除,之后再尝试加入队列

手动创建一个线程池

   public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,//核心数
                5,//最大线程数
                3,//超时了没有人调用就会释放
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),// 阻塞队列
                Executors.defaultThreadFactory(),// 线程工厂:创建线程的,一般不用动      
                new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略


        try {
            //最大承载:队列容量+最大线程数
            for (int i = 0; i <9; i++) {
                //使用线程池之后,使用线程池来创建线程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束时,关闭线程池
            threadPool.shutdown();
        }
    }

注意点:
最大承载:队列容量+最大线程数

密集型(调优)

之前的学习中,我们可以创建线程池了,但是如何确定线程池的大小呢?

  • CPU 密集型 :cpu使用率较高(也就是一些复杂运算,逻辑处理),所以线程数一般只需要cpu核数的线程就可以了。 这一类型的在开发中多出现的一些业务复杂计算和逻辑处理过程中。
  • IO 密集型:cpu使用率较低,程序中会存在大量I/O操作占据时间,导致线程空余时间出来,所以通常就需要开cpu核数的两倍的线程, 当线程进行I/O操作cpu空暇时启用其他线程继续使用cpu,提高cpu使用率 通过上述可以总结出:线程的最佳数量: 最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目 线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值