线程池总结

操作系统中,线程是操作系统调度的最小单位,同时线程又是一种受限的系统资源,线程不可能无限制的产生,并且线程的创建和销毁都有相应的开销。当系统存在大量线程时,系统通过时间片轮转的方式调度每个线程,因此线程不可能做到绝对的并行,除非线程数量小于CPU的核心数。

使用多线程的目的:尽可能多的使用CPU的资源,让效率最大化。多个线程完成多项任务,提高系统的效率。当线程数量越来越多时,操作系统将会花费更多时间去理清线程之间的关系,所以需要使用线程池。


线程池:初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程(提高线程复用,减少性能开销)。

使用线程池的原因:减少创建和销毁线程的次数,每个线程都可以被重复利用,节约应用内存

 1. 线程池改进了一个应用程序的响应时间。复用已有线程而不是新建线程。

 2. 线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。

3.线程池根据当前在系统中运行的进程来优化线程时间片。

4. 线程池允许我们开启多个任务而不用为每个线程设置属性。

5. 线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。

6. 线程池可以用来解决处理一个特定请求最大线程数量限制问题。有效控制线程池的最大并发数,避免大量线程之间互相抢占系统资源而导致阻塞的现象

7.能够对线程简单的管理,定时执行,间隔循环执行等


    Executor是一个接口,真正实现类为ThreadPoolExecutor,所提供的四类线程池通过Executor所提供的工厂方法而得到。

    构造方法:public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory)



corePoolSize:

线程的核心线程数。

默认情况下,核心线程数会在线程中一直存活,即使它们处于闲置状态。

如果将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,那么核心线程就会存在超时策略,这个时间间隔有keepAliveTime所决定,当等待时间超过keepAliveTime所指定的时长后,核心线程就会被停止。


maximumPoolSize

线程池所能容纳的最大线程数。

当活动线程数达到这个数值后,后续的新任务将会被阻塞。


keepAliveTime

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


unit

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

TimeUnit.NANOSECONDS 纳秒

TimeUnit.MICROSECONDS 微秒

TimeUnit.MILLISECONDS 毫秒

TimeUnit.SECONDS    秒

TimeUnit.MINUTES    分钟

TimeUnit.HOURS      小时

TimeUnit.DAYS      天


workQueue

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

这个任务队列是BlockQueue类型,属于阻塞队列,就是当队列为空的时候,此时取出任务的操作会被阻塞,等待任务加入队列中不为空的时候,才能进行取出操作,而在满队列的时候,添加操作同样被阻塞。


threadFactory

线程工厂,为线程池提供创建新线程的功能。ThreadFactory是一个接口,它只有一个方法newThread(Runnable r),用来创建线程。


RejectedExecutionHandler

当线程无法执行新任务时(一般是由于线程池中的线程数量已经达到最大数或者线程池关闭导致的),默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException。



submit()和execute()的区别

submit()其实还是需要调用execute()去执行任务,而submit()和execute()本质上的不同是submit()将包装好的任务进行了返回.



ThreadPoolExecutor执行任务逻辑规则:

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

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

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

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



四种常用线程池

1.newFixedThreadPool

       该模式全部由核心线程去实现,并不会被回收,没有超时限制和任务队列的限制,会创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。实现代码如下:

public static ExecutorService newFixedThreadPool(int mThreads){      

      return new ThreadPoolExecutor(mThreads,mThreads,0L,TimeUtil.MILLISECONDS,new                        LinkedBlockingQueue());

}

2.newCachedThreadPool

          该模式下线程数量不定的线程池,只有非核心线程,最大值为Integer.MAX_VALUE,会创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。实现代码如下:

public static ExecutorService newCachedThreadPool(){

      return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUtil.SECONDS,new                       SynchronousQueue());

}

3.newScheduledThreadPool

         该模式下核心线程是固定的,非核心线程没有限制,非核心线程闲置时会被回收。会创建一个定长线程池,执行定时任务和固定周期的任务。实现代码如下:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){

            return new SchduledThreadPoolExecutor(corePoolSize)

}

public SchduledThreadPoolExecutor(int corePoolSize){

       super(corePoolSize,Integer.MAX_VALUE,0,NANOSECONDS,new DelayedWorkQueue());

}

4.newSingleThreadExecutor

        该模式下线程池内部只有一个线程,所有的任务都在一个线程中执行,会创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。实现代码如下:

public static ExecutorService newSingleThreadExecutor(){

          return new FinalizableDelegatedExecutorService(newThreadPoolExecutor(1,1,

                      0L,TimeUtil.MILLISECONDS,new LinkedBlockingQueue()));

}


这四种线程池都有OOM风险

1. FixedThreadPool 和 SingleThreadPool : 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM;

2. CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。


参考:安卓开发艺术探索 鸿洋公众号,阿里巴巴android开发规范等

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342