当前位置:   article > 正文

Android线程池ThreadPool浅析_android pid tid

android pid tid

1.传统开启线程方式:

  1. new Thread(new Runnable() {
  2. @Override
  3. public void run() {
  4. 。。。。。。
  5. }
  6. }).start();

new Thread的弊端如下:

a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,线程过多,导致各个线程竞争抢夺CPU执行权,线程的频繁切换导致效率的降低,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。

2.使用线程池的好处

1.重用线程池中的线程,避免频繁创建进而导致的频繁GC所带来的性能开销

2.能有效的控制线程最大并发数,合理使用系统资源,避免大量线程之间因相互抢占资源而导致的阻塞现象

3.可以有效的控制线程的执行,比如定时执行,取消执行等

Android中的线程池的概念来源于java中的ExecutorExecutor是一个接口,真正的线程池的实现为ThreadPoolExecutor

  1. public interface Executor {
  2. void execute(Runnable var1);
  3. }
  4. public interface ExecutorService extends Executor {}
  5. public abstract class AbstractExecutorService implements ExecutorService {}
  6. public class ThreadPoolExecutor extends AbstractExecutorService {
  7. ..........
  8. public void execute(Runnable command) {
  9. if (command == null) {
  10. throw new NullPointerException();
  11. } else {
  12. int c = this.ctl.get();
  13. if (workerCountOf(c) < this.corePoolSize) {
  14. if (this.addWorker(command, true)) {
  15. return;
  16. }
  17. c = this.ctl.get();
  18. }
  19. if (isRunning(c) && this.workQueue.offer(command)) {
  20. int recheck = this.ctl.get();
  21. if (!isRunning(recheck) && this.remove(command)) {
  22. this.reject(command);
  23. } else if (workerCountOf(recheck) == 0) {
  24. this.addWorker((Runnable)null, false);
  25. }
  26. } else if (!this.addWorker(command, false)) {
  27. this.reject(command);
  28. }
  29. }
  30. }
  31. .........
  32. }

下面介绍ThreadPoolExecutor的构造方法中各个参数的含义:

  1. // 一个比较常用的构造方法
  2. public ThreadPoolExecutor (int corePoolSize,
  3. int maximumPoolSize,
  4. long keepAliveTime,
  5. TimeUnit unit,
  6. BlockingQueue<Runnable workQueue>,
  7. ThreadFactory threadFactory )

corePoolSize:

线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使它们处于闲置状态。如果将ThreadPoolExecutorallowCoreThreadTimeOut属性设置为true,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由keepAliveTime所指定,当等待时间超时超过keepAliveTime所指定的时长后,核心线程会被终止。

maxumumPoolSize:

线程池所能容纳的最大线程数,当活动线程达到这个数值后,后续的新任务将会被阻塞。

keepAliveTime:

非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收。当ThreadPoolExecutorallowCoreThreadTimeOut属性设置为true,keepAliveTime同样会作用于核心线程

unit:

用于指定keepAliveTime参数的时间单位,这是一个枚举,常用的有TimeUnit.MILLSECONDS(毫秒),TimeUnit.SECONDS(秒)以及TimeUnit.MINUTES(分钟)。

workQueue:

线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数中

threadFactory:

线程工厂,为线程池提供创建新线程的功能。ThreadFactory是一个接口,它只有一个方法:

Thread newThread(Runnable var1);

线程池的使用流程如下:

  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. // a. 遍历线程池中的所有工作线程
  24. // b. 逐个调用线程的interrupt()中断线程(注:无法响应中断的任务可能永远无法终止)
  25. // 也可调用shutdownNow()关闭线程:threadPool.shutdownNow()
  26. // 二者区别:
  27. // shutdown:设置 线程池的状态 为 SHUTDOWN,然后中断所有没有正在执行任务的线程
  28. // shutdownNow:设置 线程池的状态 为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
  29. // 使用建议:一般调用shutdown()关闭线程池;若任务不一定要执行完,则调用shutdownNow()

3. 常见的4类功能线程池

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

  • 定长线程池(FixedThreadPool
  • 定时线程池(ScheduledThreadPool )
  • 可缓存线程池(CachedThreadPool
  • 单线程化线程池(SingleThreadExecutor

即 对于上述4类线程池,Java已根据 应用场景 配置好核心参数

3.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. // 3. 向线程池提交任务:execute()
  10. fixedThreadPool.execute(task);
  11. // 4. 关闭线程池
  12. fixedThreadPool.shutdown();

举个例子:

  1. // 1. 创建定长线程池对象 & 设置线程池线程数量固定为4
  2. ExecutorService pool = Executors.newFixedThreadPool(4);
  3. Thread thread;
  4. //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
  5. for (int i = 0; i < 10; i++) {
  6. thread = new Thread(new Runnable() {
  7. @Override
  8. public void run() {
  9. System.out.println(Thread.currentThread().getName() + "正在执行。。。");
  10. }
  11. });
  12. pool.execute(thread);//向线程池提交任务
  13. }
  14. pool.shutdown(); //关闭线程池
  15. //打印结果
  16. pool-1-thread-1正在执行。。。
  17. pool-1-thread-4正在执行。。。
  18. pool-1-thread-1正在执行。。。
  19. pool-1-thread-4正在执行。。。
  20. pool-1-thread-3正在执行。。。
  21. pool-1-thread-2正在执行。。。
  22. pool-1-thread-3正在执行。。。
  23. pool-1-thread-4正在执行。。。
  24. pool-1-thread-1正在执行。。。
  25. pool-1-thread-2正在执行。。。

3.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();

举个例子:

  1. // 1. 创建 定时线程池对象 & 设置线程池线程数量固定为2
  2. ScheduledExecutorService pool= Executors.newScheduledThreadPool(2);
  3. Thread thread;
  4. long a=System.currentTimeMillis();
  5. //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
  6. for (int i = 0; i < 10; i++) {
  7. thread = new Thread(new Runnable() {
  8. @Override
  9. public void run() {
  10. long b=System.currentTimeMillis();
  11. System.out.println(Thread.currentThread().getName() +"延迟"+ (b-a)/1000+"S执行");
  12. }
  13. });
  14. pool.schedule(thread,3,TimeUnit.SECONDS);//向线程池提交任务
  15. }
  16. pool.shutdown(); //关闭线程池
  17. 输出结果//
  18. pool-1-thread-2延迟3S执行
  19. pool-1-thread-1延迟3S执行
  20. pool-1-thread-1延迟3S执行
  21. pool-1-thread-2延迟3S执行
  22. pool-1-thread-1延迟3S执行
  23. pool-1-thread-2延迟3S执行
  24. pool-1-thread-1延迟3S执行
  25. pool-1-thread-2延迟3S执行
  26. pool-1-thread-1延迟3S执行
  27. pool-1-thread-2延迟3S执行

定期执行:

  1. // 1. 创建 定时线程池对象 & 设置线程池线程数量固定为1
  2. ScheduledExecutorService pool= Executors.newScheduledThreadPool(1);
  3. //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
  4. pool.scheduleAtFixedRate(new Runnable() {
  5. @Override
  6. public void run() {
  7. System.out.println(Thread.currentThread().getName() );
  8. }
  9. }, 1, 3, TimeUnit.SECONDS);//表示延迟1秒后每3秒执行一次。

3.3 可缓存线程池(CachedThreadPool)

  • 特点:只有非核心线程,并且最大线程数为Integer.MAX_VALUE。由于Integer.MAX_VALUE是一个很大的数(2147483647),实际上就相当于最大线程数可以任意大。灵活回收空闲线程(具备超时机制(超过60秒闲置线程就会被回收),全部回收时几乎不占系统资源)、新建线程(无线程可用时)

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. //那么会复用执行第一个任务的线程,而不用每次新建线程。

3.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();

举个例子:

  1. ExecutorService pool = Executors.newSingleThreadExecutor();
  2. Thread thread;
  3. //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
  4. for (int i = 0; i < 10; i++) {
  5. thread = new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. System.out.println(Thread.currentThread().getName() + "正在执行。。。");
  9. }
  10. });
  11. pool.execute(thread);//向线程池提交任务
  12. }
  13. pool.shutdown(); //关闭线程池
  14. //输出日志//
  15. pool-1-thread-1正在执行。。。
  16. pool-1-thread-1正在执行。。。
  17. pool-1-thread-1正在执行。。。
  18. pool-1-thread-1正在执行。。。
  19. pool-1-thread-1正在执行。。。
  20. pool-1-thread-1正在执行。。。
  21. pool-1-thread-1正在执行。。。
  22. pool-1-thread-1正在执行。。。
  23. pool-1-thread-1正在执行。。。
  24. pool-1-thread-1正在执行。。。

3.5 常见线程池 总结 & 对比

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/240434
推荐阅读
相关标签
  

闽ICP备14008679号