Android-Threadpool

     关于线程我不想再说什么,感兴趣的同学可以看我之前写过的一篇文章:Android-多线程,这里对线程有一个比较详细的解释。

Android-多线程 - 简书

我们今天直入重点:聊意料我们常用的线程池.

一:

1.什么是线程池?

听名字也不难理解,线程池就是线程的集合,用来控制管理线程,控制并发数等,减少了线程创建和销毁的次数。提高线程的复用率,降低性能的损耗。

2.有哪些线程池呢?

        首先我们先从源码的角度开始分析,先创建一个线程池,然后一步步查看它的源码,分析其关系。

        直接上图:

然后一步步查看:从最上面的接口开始。

首先。Executor是一个类的实现接口,里面有一个执行方法:execute().,这就是线程池的起源,属于线程的一个执行工具,并不是真正的线程池。

如图,我们可以看到ExecutorService接口继承自我们之前的Executor工具类,它里面有好多的api方法,是真正的线程池接口。

然后呢,AbstractExecutorService是一个抽象方法,它实现了ExecutorService接口,可以实现其抽象方法, 也可以进行自定义。

最后ThreadPoolExecutor才是我们的具体实现类,Android中的线程池都是 直接或间接通过配置ThreadPoolExecutor 来实现不同的线程池。

我们来看一下它的构造方法:

  其实ThreadPoolExecutor有四种构造方法,我们举例其中最多的一个讲一下。

(1)  //核心线程数 

int corePoolSize,  

注:线程池新建线程的时候,如果当前线程总数小于 corePoolSize ,则新建的是核心线程;如果超过corePoolSize,则新建的是非核心线程。

(2)  //最大线程数,活动线程数量超过它,后续任务就会自动排队                    

int maximumPoolSize

线程总数= 核心线程数 + 非核心线程数。

(3)    //超时时长,非核心线程如果长时间闲置,超过这个时长便被回收    ,但如果设置allowCoreThreadTimeOut = true,则会作用于核心线程 ,超过时长也会被回收。  

long keepAliveTime,                            

(4)   //枚举类型,设置keepAliveTime的单位,MILLISECONDS : 毫秒 、SECONDS : 秒、MINUTES : 分、HOURS : 小时、DAYS : 天

TimeUnit unit,  

//缓冲任务队列,线程池的execute方法会将Runnable对象存储起来,当所有的核心线程都有活干,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。

BlockingQueue workQueue,  

(5)  //线程工厂接口,只有一个new Thread(Runnable r)方法,可以认为是线程池创建新线程  

BlockingQueue有四种队列类型:(1)SynchronousQueue:(同步队列)

                                                    (2)LinkedBlockingQueue(链表阻塞队列)

                                                    (3)ArrayBlockingQueue(数组阻塞队列)

                                                    (4)DelayQueue(延迟队列)

SynchronousQueue:(同步队列)这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,但如果所有的线程都在工作呢?这种情况下,SynchronousQueue就会新建一个线程来处理这个任务。所以为了保证不出现(线程数达到了maximumPoolSize而不能新建线程)的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大,去规避这个使用风险。

LinkedBlockingQueue(链表阻塞队列):这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize

ArrayBlockingQueue(数组阻塞队列):可以限定队列的长度(既然是数组,那么就限定了大小),接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误

DelayQueue(延迟队列):队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

(6)   //创建线程的方式

       ThreadFactory threadFactory  这是一个接口,new它的时候需要实现他的Thread newThread(Runnable r)方法。

(7)   // 这个主要是用来抛异常的,如果线程无法执行新任务一般会抛一个RejectedExecutionException异常。

       RejectedExecutionHandler handler

二:ok,讲完了这些,我们来看看如何使用线程池?

线程池新添加了任务,那么线程池是如何运行的呢,总结:

1:如果线程数量未达到corePoolSize,则新建一个线程(核心线程)执行任务

2:如果线程数量达到了corePools,则将任务移入队列等待

3:如果队列已满,新建线程(非核心线程)执行任务

4:如果队列已满,总线程数又达到了maximumPoolSize,就会由RejectedExecutionHandler抛出异常

但我们不需要这么费劲,java已经给我们提供了四种线程池,,来搞一下。

第一种:

A:定长线程池  newFixedThreadPool ,只有核心线程,数量固定,不会被回收。可控制线程最大并发数,超出的线程会在队列中等待。其中nThreads参数是我们要创建几个线程。如果所有线程都出于运行状态,提交额外的任务,他们会在队列中等待,直到有一个线程可用为止。

使用:

第二种:

B:缓存线程池 newCacheThreadPool,只有非核心线程,最大线程数不做限制,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。空闲线程超过60秒会被终止并从线程池里移除缓存。

使用:

第三种:

C:定长任务线程池,ScheduledExecutorService.支持定时及周期性任务执行

corePoolSize 参数是指在池中保留的线程数,即使它们是空闲的。这个函数最终会返回一个新创建的调度线程池.

使用:

第四种:

    D:newSingleThreadExecutor 创建一个单线程的线程池,用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个单独的线程终止是因为在执行前异常或者终止,若需要执行后续的任务,那么就需要一个新的去替代它,返回的是一个重新创建的单线程去执行。

使用:

突然觉得直接写用法,不来个demo,是不是小伙伴不容易理解呀。那好。我们以缓存线程池为例.来个场景演示。大家都知道下载文件吧,我们就整这个。多线程下载多个文件。

    上一波图:

        咳咳,初始化UI就.......省了吧。

效果:

点击下载文件可以看到是同一个线程池,两个线程平行。

文件A和文件C是同一个线程在下载,也就是在线程thread-1下载文件A完毕后,点击下载文件C,并没有在重新在创建线程,而是复用了文件A下载的thread-1继续下载文件C。

好了就这么多,拜拜。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android-多线程

            通俗的说:我们平日里打开的QQ,微信,简书,都是一个进程。进程是程序的一次动态执行过程,它需要经历从代码加载,代码执行到执行完毕的一个完整的过程...

    android_薛之涛
  • Android-Handler机制

    参考:https://mp.weixin.qq.com/s/AvpOq6eh-IBDJj2SXa_wXw https://www.jianshu.com/p/...

    android_薛之涛
  • ViewPager2:官方Viewpager升级版来临

    这两天浏览安卓开发者官网的时候,发现google悄然推出了一个新的控件:ViewPager2,一看名称就知道这是一个和我们常用的ViewPager功能相似的控件...

    android_薛之涛
  • Java面试题汇总---整理版(附答案)

    spring能够很好的和各大框架整合,它通过IOC容器管理了对象的创建和销毁 工厂模式。在使用hiberna,mybatis的时候,不用每次都编写提交的事务的...

    攻城狮的那点事
  • 多线程?怎么用?

    进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

    故里
  • 读书笔记《Java并发编程的艺术 - 方腾飞》- Java并发编程

    在Java中, 我们可以通过 priority 属性来设置线程的优先级, 参数为 1 ~ 10 参数越大, 代表优先级越高, 默认的优先级为 5

    lvgo
  • 多线程开发,先学会线程池吧

    在实际开发场景中,我们经常要使用多线程开发应用,比如实现异步操作,或者为了提高程序的效率等等。但是以前我见过有实习生在使用的时候是直接new Runable()...

    java技术爱好者
  • 并发编程面试题汇总

    thinkwon.blog.csdn.net/article/details/104863992

    Java旅途
  • 小白科普:线程和线程池

    第一个问题问题就是为什么要多线程啊, 我看了操作系统中的多进程管理,不是挺好的吗? 多线程似乎没有必要啊!

    阿凯
  • Thread方法

    这个方法返回线程的 ID 值,类型为 long。线程的 ID 在线程的整个生命周期中都不变。

    宇宙之一粟

扫码关注云+社区

领取腾讯云代金券