发新帖
开启左侧

Android多线程:线程池ThreadPool 全面解析

[复制链接]
10 0



前言


  • 对于多线程,大家应该很熟悉。但是,大家了解线程池吗?
  • 今天,我将带大家全部学习关于线程池的所有知识。
目录





1. 简介





2. 工作原理

2.1 核心参数


  • 线程池中有6个核心参数,具体如下





  • 上述6个参数的配置 决定了 线程池的功能,具体设置时机 = 创建 线程池类对象时 传入

  • ThreadPoolExecutor类 = 线程池的真正实现类
  • 开发者可根据不同需求 配置核心参数,从而实现自定义线程池
  1. // 创建线程池对象如下
  2. // 通过 构造方法 配置核心参数
  3.    Executor executor = new ThreadPoolExecutor(
  4.                                               CORE_POOL_SIZE,
  5.                                               MAXIMUM_POOL_SIZE,
  6.                                               KEEP_ALIVE,
  7.                                               TimeUnit.SECONDS,
  8.                                               sPoolWorkQueue,
  9.                                               sThreadFactory
  10.                                                );

  11. // 构造函数源码分析
  12.     public ThreadPoolExecutor (int corePoolSize,
  13.                                int maximumPoolSize,
  14.                                long keepAliveTime,
  15.                                TimeUnit unit,
  16.                                BlockingQueue<Runnable workQueue>,
  17.                                ThreadFactory threadFactory )
复制代码
注:Java 里已内置4种常用的线程池(即 已经配置好核心参数),下面会详细说明
2.2 内部原理逻辑

当线程池运行时,遵循以下工作逻辑




3. 使用流程

线程池的使用流程如下
  1. // 1. 创建线程池
  2.    // 创建时,通过配置线程池的参数,从而实现自己所需的线程池
  3.    Executor threadPool = new ThreadPoolExecutor(
  4.                                               CORE_POOL_SIZE,
  5.                                               MAXIMUM_POOL_SIZE,
  6.                                               KEEP_ALIVE,
  7.                                               TimeUnit.SECONDS,
  8.                                               sPoolWorkQueue,
  9.                                               sThreadFactory
  10.                                               );
  11.     // 注:在Java中,已内置4种常见线程池,下面会详细说明

  12. // 2. 向线程池提交任务:execute()
  13.     // 说明:传入 Runnable对象
  14.        threadPool.execute(new Runnable() {
  15.             @Override
  16.             public void run() {
  17.                 ... // 线程执行任务
  18.             }
  19.         });

  20. // 3. 关闭线程池shutdown()
  21.   threadPool.shutdown();
  22.   
  23.   // 关闭线程的原理
  24.   // a. 遍历线程池中的所有工作线程
  25.   // b. 逐个调用线程的interrupt()中断线程(注:无法响应中断的任务可能永远无法终止)

  26.   // 也可调用shutdownNow()关闭线程:threadPool.shutdownNow()
  27.   // 二者区别:
  28.   // shutdown:设置 线程池的状态 为 SHUTDOWN,然后中断所有没有正在执行任务的线程
  29.   // shutdownNow:设置 线程池的状态 为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
  30.   // 使用建议:一般调用shutdown()关闭线程池;若任务不一定要执行完,则调用shutdownNow()
复制代码
4. 常见的4类功能线程池

根据参数的不同配置,Java中最常见的线程池有4类:

  • 定长线程池(FixedThreadPool)
  • 定时线程池(ScheduledThreadPool )
  • 可缓存线程池(CachedThreadPool)
  • 单线程化线程池(SingleThreadExecutor)
即 对于上述4类线程池,Java已根据 应用场景 配置好核心参数
4.1 定长线程池(FixedThreadPool)


  • 特点:只有核心线程 & 不会被回收、线程数量固定、任务队列无大小限制(超出的线程任务会在队列中等待)
  • 应用场景:控制线程最大并发数
  • 具体使用:通过 Executors.newFixedThreadPool() 创建
  • 示例:
  1. // 1. 创建定长线程池对象 & 设置线程池线程数量固定为3
  2. ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

  3. // 2. 创建好Runnable类线程对象 & 需执行的任务
  4. Runnable task =new Runnable(){
  5.   public void run(){
  6.     System.out.println("执行任务啦");
  7.      }
  8.     };
  9.         
  10. // 3. 向线程池提交任务:execute()
  11. fixedThreadPool.execute(task);
  12.         
  13. // 4. 关闭线程池
  14. fixedThreadPool.shutdown();
复制代码
4.2 定时线程池(ScheduledThreadPool )


  • 特点:核心线程数量固定、非核心线程数量无限制(闲置时马上回收)
  • 应用场景:执行定时 / 周期性 任务
  • 使用:通过Executors.newScheduledThreadPool()创建
  • 示例:
  1. // 1. 创建 定时线程池对象 & 设置线程池线程数量固定为5
  2. ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

  3. // 2. 创建好Runnable类线程对象 & 需执行的任务
  4. Runnable task =new Runnable(){
  5.        public void run(){
  6.               System.out.println("执行任务啦");
  7.           }
  8.     };
  9. // 3. 向线程池提交任务:schedule()
  10. scheduledThreadPool.schedule(task, 1, TimeUnit.SECONDS); // 延迟1s后执行任务
  11. scheduledThreadPool.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);// 延迟10ms后、每隔1000ms执行任务

  12. // 4. 关闭线程池
  13. scheduledThreadPool.shutdown();
复制代码
4.3 可缓存线程池(CachedThreadPool)


  • 特点:只有非核心线程、线程数量不固定(可无限大)、灵活回收空闲线程(具备超时机制,全部回收时几乎不占系统资源)、新建线程(无线程可用时)
任何线程任务到来都会立刻执行,不需要等待

  • 应用场景:执行大量、耗时少的线程任务
  • 使用:通过Executors.newCachedThreadPool()创建
  • 示例:
  1. // 1. 创建可缓存线程池对象
  2. ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

  3. // 2. 创建好Runnable类线程对象 & 需执行的任务
  4. Runnable task =new Runnable(){
  5.   public void run(){
  6.         System.out.println("执行任务啦");
  7.             }
  8.     };

  9. // 3. 向线程池提交任务:execute()
  10. cachedThreadPool.execute(task);

  11. // 4. 关闭线程池
  12. cachedThreadPool.shutdown();

  13. //当执行第二个任务时第一个任务已经完成
  14. //那么会复用执行第一个任务的线程,而不用每次新建线程。
复制代码
4.4 单线程化线程池(SingleThreadExecutor)


  • 特点:只有一个核心线程(保证所有任务按照指定顺序在一个线程中执行,不需要处理线程同步的问题)
  • 应用场景:不适合并发但可能引起IO阻塞性及影响UI线程响应的操作,如数据库操作,文件操作等
  • 使用:通过Executors.newSingleThreadExecutor()创建
  • 示例:
  1. // 1. 创建单线程化线程池
  2. ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

  3. // 2. 创建好Runnable类线程对象 & 需执行的任务
  4. Runnable task =new Runnable(){
  5.   public void run(){
  6.         System.out.println("执行任务啦");
  7.             }
  8.     };

  9. // 3. 向线程池提交任务:execute()
  10. singleThreadExecutor.execute(task);

  11. // 4. 关闭线程池
  12. singleThreadExecutor.shutdown();

复制代码
4.5 常见线程池 总结 & 对比





5. 总结


  • 阅读本文后,相信你已经非常了解线程池 & 用法
  • 接下来,我会继续讲解Android开发中关于多线程的知识,具体包括Thread类、Handler、HandlerThread等等,有兴趣可以继续关注Carson_Ho的安卓开发笔记
请点赞!因为你的鼓励是我写作的最大动力!
相关文章阅读
Android开发:最全面、最易懂的Android屏幕适配解决方案
Android开发:史上最全的Android消息推送解决方案
Android开发:最全面、最易懂的Webview详解
Android开发:JSON简介及最全面解析方法!
Android四大组件:Service服务史上最全面解析
Android四大组件:BroadcastReceiver史上最全面解析
欢迎关注Carson_Ho的简书!

不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度


*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表