当前位置:   article > 正文

Android开发中的线程池使用_android 线程池使用

android 线程池使用

一、前言

        既然Android中已经有了线程的概念,那么为什么需要使用线程池呢?我们从两个方面给出使用线程池的原因。

        首先线程的新建和销毁都是存在性能上的消耗的,如果一个时间段有大量的网络请求,那么就需要多个线程的创建与销毁,性能上的损耗可想而知。

        其次多个线程的存在也会占用CPU的执行时间段。我们知道如果只有一个CPU存在,那么线程的执行都是CPU轮流将执行时间分配给每一个线程。如果同时有多个子线程存在,那么相应的分配到主线程的CPU执行时间也会变少,这样App很大可能会出现卡顿现象。
鉴于上述两方面的原因,我们引进来了线程池这样一个概念,线程的创建、调度、销毁等都是由线程池来管理,这样就可以做到线程的重用,不必每次都新建一个线程,减少了线程创建和销毁的性能损耗。同时线程池会限制创建线程的个数,让App中的线程个数保持在一个可控的范围,这样也可以控制多个线程抢占主线程的资源。


 

二、线程池的优点

1.重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
2.能有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
3.能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。

三、ThreadPoolExecutor

        Android中的线程池的概念来源于java中的Executor,  Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor.  ThreadPoolExecutor提供了一系列参数来配置线程池,通过不同的参数可以创建不同类型的线程池.

        ThreadPoolExecutor是线程池的真正实现,它的构造方法提供一系列参数来配置线程池.

我们来看看它的构造方法

源码路径: libcore/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java

  1. // Public constructors and methods
  2. /**
  3. * Creates a new {@code ThreadPoolExecutor} with the given initial
  4. * parameters and default thread factory and rejected execution handler.
  5. * It may be more convenient to use one of the {@link Executors} factory
  6. * methods instead of this general purpose constructor.
  7. *
  8. * @param corePoolSize the number of threads to keep in the pool, even
  9. * if they are idle, unless {@code allowCoreThreadTimeOut} is set
  10. * @param maximumPoolSize the maximum number of threads to allow in the
  11. * pool
  12. * @param keepAliveTime when the number of threads is greater than
  13. * the core, this is the maximum time that excess idle threads
  14. * will wait for new tasks before terminating.
  15. * @param unit the time unit for the {@code keepAliveTime} argument
  16. * @param workQueue the queue to use for holding tasks before they are
  17. * executed. This queue will hold only the {@code Runnable}
  18. * tasks submitted by the {@code execute} method.
  19. * @throws IllegalArgumentException if one of the following holds:<br>
  20. * {@code corePoolSize < 0}<br>
  21. * {@code keepAliveTime < 0}<br>
  22. * {@code maximumPoolSize <= 0}<br>
  23. * {@code maximumPoolSize < corePoolSize}
  24. * @throws NullPointerException if {@code workQueue} is null
  25. */
  26. public ThreadPoolExecutor(int corePoolSize,
  27. int maximumPoolSize,
  28. long keepAliveTime,
  29. TimeUnit unit,
  30. BlockingQueue<Runnable> workQueue) {
  31. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
  32. Executors.defaultThreadFactory(), defaultHandler);
  33. }

对应的参数说明:

四、线程池分类

定义的源码路径为: /libcore/ojluni/src/main/java/java/util/concurrent/Executors.java

根据参数的不同配置,Java内置了4种常用线程池:

  • 定长线程池(FixedThreadPool) 调用Executors.newFixedThreadPool()创建
  • 定时线程池(ScheduledThreadPool )调用Executors.newScheduledThreadPool()创建
  • 缓存线程池(CachedThreadPool)调用Executors.newCachedThreadPool()创建
  • 单例线程池(SingleThreadExecutor)调用Executors.newSingleThreadExecutor()创建

 特点和对比图

总结的思维导图:

五、使用方法

  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()

六、Demo

我们通过源码来看下是怎么使用的:

源码片段:

/Dialer/java/com/android/voicemail/impl/transcribe/TranscriptionService.java

1. 创建一个单例线程池

  1. private ExecutorService getExecutorService() {
  2. if (executorService == null) {
  3. // The common use case is transcribing a single voicemail so just use a single thread executor
  4. // The reason we're not using DialerExecutor here is because the transcription task can be
  5. // very long running (ie. multiple minutes).
  6. executorService = Executors.newSingleThreadExecutor();
  7. }
  8. return executorService;
  9. }

2. 调用 execute(Runnable  runnable)方法,执行任务

  1. activeTask =
  2. configProvider.shouldUseSyncApi()
  3. ? new TranscriptionTaskSync(
  4. this, new Callback(), workItem, getClientFactory(), configProvider)
  5. : new TranscriptionTaskAsync(
  6. this, new Callback(), workItem, getClientFactory(), configProvider);
  7. //执行任务
  8. getExecutorService().execute(activeTask);

3. 任务执行完毕后,调用shutdown方法

  1. @Override
  2. @MainThread
  3. public void onDestroy() {
  4. if (executorService != null) {
  5. executorService.shutdownNow();
  6. executorService = null;
  7. }
  8. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号