java多线程-线程池

小灰灰 2022-09-03 12:26 458阅读 0赞

线程池-基本原理

概述 :

​ 提到池,大家应该能想到的就是水池。水池就是一个容器,在该容器中存储了很多的水。那么什么是线程池呢?线程池也是可以看做成一个池子,在该池子中存储很多个线程。

线程池存在的意义:

​ 系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理是对系

​ 统资源的消耗,这样就有点”舍本逐末”了。针对这一种情况,为了提高性能,我们就可以采用线程池。线程池在启动的时,会创建大量空闲线程,当我们向线程池提交任务的时,线程池就会启动一个线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次返回到线程池中称为空闲状态。等待下一次任务的执行。

1.6 线程池-Executors默认线程池

概述 : JDK对线程池也进行了相关的实现,在真实企业开发中我们也很少去自定义线程池,而是使用JDK中自带的线程池。

我们可以使用Executors中所提供的静态方法来创建线程池

  • Executer:线程池的顶级接口
  • Executers工厂类;通过此类可以创建一个线程池
  • ExecuterService:线程池接口,可通过submit提交


















    方法 介绍
    static ExecutorService newCachedThreadPool() 创建一个默认的线程池
    static newFixedThreadPool(int nThreads) 创建一个指定最多线程数量的线程池

代码实现 :

  1. package com.itheima.mythreadpool;
  2. //static ExecutorService newCachedThreadPool() 创建一个默认的线程池
  3. //static newFixedThreadPool(int nThreads) 创建一个指定最多线程数量的线程池
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. public class MyThreadPoolDemo {
  7. public static void main(String[] args) throws InterruptedException {
  8. //1,创建一个默认的线程池对象.池子中默认是空的.默认最多可以容纳int类型的最大值.
  9. ExecutorService executorService = Executors.newCachedThreadPool();
  10. //Executors --- 可以帮助我们创建线程池对象
  11. //ExecutorService --- 可以帮助我们控制线程池
  12. executorService.submit(()->{
  13. System.out.println(Thread.currentThread().getName() + "在执行了");
  14. });
  15. //Thread.sleep(2000);
  16. executorService.submit(()->{
  17. System.out.println(Thread.currentThread().getName() + "在执行了");
  18. });
  19. executorService.shutdown();
  20. }
  21. }

1.7 线程池-Executors创建指定上限的线程池

使用Executors中所提供的静态方法来创建线程池

​ static ExecutorService newFixedThreadPool(int nThreads) : 创建一个指定最多线程数量的线程池

代码实现 :

  1. package com.itheima.mythreadpool;
  2. //static ExecutorService newFixedThreadPool(int nThreads)
  3. //创建一个指定最多线程数量的线程池
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.ThreadPoolExecutor;
  7. public class MyThreadPoolDemo2 {
  8. public static void main(String[] args) {
  9. //参数不是初始值而是最大值
  10. ExecutorService executorService = Executors.newFixedThreadPool(10);
  11. ThreadPoolExecutor pool = (ThreadPoolExecutor) executorService;
  12. System.out.println(pool.getPoolSize());//0
  13. executorService.submit(()->{
  14. System.out.println(Thread.currentThread().getName() + "在执行了");
  15. });
  16. executorService.submit(()->{
  17. System.out.println(Thread.currentThread().getName() + "在执行了");
  18. });
  19. System.out.println(pool.getPoolSize());//2
  20. // executorService.shutdown();
  21. }
  22. }

1.8 线程池-ThreadPoolExecutor

创建线程池对象 :

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);

代码实现 :

  1. package com.itheima.mythreadpool;
  2. import java.util.concurrent.ArrayBlockingQueue;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.ThreadPoolExecutor;
  5. import java.util.concurrent.TimeUnit;
  6. public class MyThreadPoolDemo3 {
  7. // 参数一:核心线程数量
  8. // 参数二:最大线程数
  9. // 参数三:空闲线程最大存活时间
  10. // 参数四:时间单位
  11. // 参数五:任务队列
  12. // 参数六:创建线程工厂
  13. // 参数七:任务的拒绝策略
  14. public static void main(String[] args) {
  15. ThreadPoolExecutor pool = new ThreadPoolExecutor(2,5,2,TimeUnit.SECONDS,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
  16. pool.submit(new MyRunnable());
  17. pool.submit(new MyRunnable());
  18. pool.shutdown();
  19. }
  20. }

1.9 线程池-参数详解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aSar9K1G-1628395811321)(D:/java/笔记/10.多线程/day22_多线程02/笔记/img/1591165506516.png)]

  1. public ThreadPoolExecutor(int corePoolSize,
  2. int maximumPoolSize,
  3. long keepAliveTime,
  4. TimeUnit unit,
  5. BlockingQueue<Runnable> workQueue,
  6. ThreadFactory threadFactory,
  7. RejectedExecutionHandler handler)
  8. corePoolSize 核心线程的最大值,不能小于0
  9. maximumPoolSize:最大线程数,不能小于等于0maximumPoolSize >= corePoolSize
  10. keepAliveTime 空闲线程最大存活时间,不能小于0
  11. unit 时间单位
  12. workQueue 任务队列,不能为null
  13. threadFactory 创建线程工厂,不能为null
  14. handler 任务的拒绝策略,不能为null

1.10 线程池-非默认任务拒绝策略

RejectedExecutionHandler是jdk提供的一个任务拒绝策略接口,它下面存在4个子类。

  1. ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。是默认的策略。
  2. ThreadPoolExecutor.DiscardPolicy 丢弃任务,但是不抛出异常 这是不推荐的做法。
  3. ThreadPoolExecutor.DiscardOldestPolicy 抛弃队列中等待最久的任务 然后把当前任务加入队列中。
  4. ThreadPoolExecutor.CallerRunsPolicy: 调用任务的run()方法绕过线程池直接执行。

注:明确线程池对多可执行的任务数 = 队列容量 + 最大线程数

案例演示1:演示ThreadPoolExecutor.AbortPolicy任务处理策略

  1. public class ThreadPoolExecutorDemo01 {
  2. public static void main(String[] args) {
  3. /** * 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */
  4. ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,
  5. new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.AbortPolicy()) ;
  6. // 提交5个任务,而该线程池最多可以处理4个任务,当我们使用AbortPolicy这个任务处理策略的时候,就会抛出异常
  7. for(int x = 0 ; x < 5 ; x++) {
  8. threadPoolExecutor.submit(() -> {
  9. System.out.println(Thread.currentThread().getName() + "---->> 执行了任务");
  10. });
  11. }
  12. }
  13. }

控制台输出结果

  1. pool-1-thread-1---->> 执行了任务
  2. pool-1-thread-3---->> 执行了任务
  3. pool-1-thread-2---->> 执行了任务
  4. pool-1-thread-3---->> 执行了任务

控制台报错,仅仅执行了4个任务,有一个任务被丢弃了

案例演示2:演示ThreadPoolExecutor.DiscardPolicy任务处理策略

  1. public class ThreadPoolExecutorDemo02 {
  2. public static void main(String[] args) {
  3. /** * 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */
  4. ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,
  5. new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardPolicy()) ;
  6. // 提交5个任务,而该线程池最多可以处理4个任务,当我们使用DiscardPolicy这个任务处理策略的时候,控制台不会报错
  7. for(int x = 0 ; x < 5 ; x++) {
  8. threadPoolExecutor.submit(() -> {
  9. System.out.println(Thread.currentThread().getName() + "---->> 执行了任务");
  10. });
  11. }
  12. }
  13. }

控制台输出结果

  1. pool-1-thread-1---->> 执行了任务
  2. pool-1-thread-1---->> 执行了任务
  3. pool-1-thread-3---->> 执行了任务
  4. pool-1-thread-2---->> 执行了任务

控制台没有报错,仅仅执行了4个任务,有一个任务被丢弃了

案例演示3:演示ThreadPoolExecutor.DiscardOldestPolicy任务处理策略

  1. public class ThreadPoolExecutorDemo02 {
  2. public static void main(String[] args) {
  3. /** * 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */
  4. ThreadPoolExecutor threadPoolExecutor;
  5. threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,
  6. new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardOldestPolicy());
  7. // 提交5个任务
  8. for(int x = 0 ; x < 5 ; x++) {
  9. // 定义一个变量,来指定指定当前执行的任务;这个变量需要被final修饰
  10. final int y = x ;
  11. threadPoolExecutor.submit(() -> {
  12. System.out.println(Thread.currentThread().getName() + "---->> 执行了任务" + y);
  13. });
  14. }
  15. }
  16. }

控制台输出结果

  1. pool-1-thread-2---->> 执行了任务2
  2. pool-1-thread-1---->> 执行了任务0
  3. pool-1-thread-3---->> 执行了任务3
  4. pool-1-thread-1---->> 执行了任务4

由于任务1在线程池中等待时间最长,因此任务1被丢弃。

案例演示4:演示ThreadPoolExecutor.CallerRunsPolicy任务处理策略

  1. public class ThreadPoolExecutorDemo04 {
  2. public static void main(String[] args) {
  3. /** * 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s */
  4. ThreadPoolExecutor threadPoolExecutor;
  5. threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,
  6. new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.CallerRunsPolicy());
  7. // 提交5个任务
  8. for(int x = 0 ; x < 5 ; x++) {
  9. threadPoolExecutor.submit(() -> {
  10. System.out.println(Thread.currentThread().getName() + "---->> 执行了任务");
  11. });
  12. }
  13. }
  14. }

控制台输出结果

  1. pool-1-thread-1---->> 执行了任务
  2. pool-1-thread-3---->> 执行了任务
  3. pool-1-thread-2---->> 执行了任务
  4. pool-1-thread-1---->> 执行了任务
  5. main---->> 执行了任务

通过控制台的输出,我们可以看到次策略没有通过线程池中的线程执行任务,而是直接调用任务的run()方法绕过线程池直接执行。

2. 原子性

2.1 volatile-问题

代码分析 :

发表评论

表情:
评论列表 (有 0 条评论,458人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java线-线

    线程池-基本原理 概述 : ​ 提到池,大家应该能想到的就是水池。水池就是一个容器,在该容器中存储了很多的水。那么什么是线程池呢?线程池也是可以看做成一个池子,在该池子