Java线程池学习(1)

来源:互联网 发布:手机桌面图标转换软件 编辑:程序博客网 时间:2024/06/05 13:06

1.为什么需要线程池

  在开发中,经常需要处理多个任务,如果使用单个线程来处理,速度会很慢,如果任务需要很快完成,这肯定不符合。很自然会想到多线程,将原有的任务分派给多个线程”同时”处理,时间会大大缩短。(其实,这并非真正的同时,而是CPU给人的错觉。我们知道,一个线程的执行并不是一次性完成的,而是分成多个片段)

  实现多线程,简单的方式就是有多少个任务,就相应开启多少个线程,即1:1。这种方式在任务量小,不需要使用太多线程的情况可以很好满足需要,但是当要处理的任务很多,大量开启线程来一一对应处理,那么很快计算机资源就会被耗尽。当然可以增加硬件,提升机器性能,但这不应成为处理此类问题的优先选项。面对的问题就是计算机资源是有限的,不允许无节制开启线程,这就是说线程对于我们而言是一种宝贵的资源,要合理利用。

  基于以上原因,有人就提出使用M:N(M<N)模式,即用少量的线程处理远大于线程数量的任务,每个线程不再只处理一个任务,而是处理多个,这就将线程复用。复用的好处,除了不会导致线程越建越多,最终受制于机器资源外,更重要的是可以节省线程创建的时间。线程的创建不同于一般类的创建,会消耗很多资源和时间,可以称之为”重量级类”。复用的概念再延伸就是”池化”,将那些比较重量级、珍贵的资源集中到一起,比如线程池,将资源的创建、使用、收回过程在一处统一管理,不仅方便维护,而且可以让业务与处理分开,调用者只需关心如何设计业务逻辑,耗时处理封装成任务提交到”线程池”。这体现了经常提到的低耦合,职责单一的思想。

  Java中已经提供了线程池工具,就是Executor框架。

2.Executor初步

类结构:

这里写图片描述

ThreadPoolExecutor是最常用的实现类,因此拿来作为我的主要学习入口。

重要概念

1.核心线程数2.最大线程数3.阻塞队列4.拒绝策略

这几个概念对于理解ThreadPoolExecutor的运行非常重要。

首先来看核心线程数(corePoolSize),它代表线程池在正常状态下可以开启线程的上限。一开始时线程池中可以使用的线程为0,新任务到来后,就会在线程池中新建一个线程,当线程数量达到corePoolSize,那么新任务就会被添加到任务队列中(前提是任务队列未满)。

任务队列,即阻塞队列,是实现了BlockingQueue的类,可以在ThreadPoolExecutor构造函数中指定,也可以不指定而使用默认的LinkedBlockingQueue。

当任务队列已满(前提是队列有界),表示核心线程来不及处理,这时线程池会添加新的线程,新的任务就交由新线程处理,当然这也有个前提,就是线程池中线程数量未达到maximumPoolSize,否则就会触发拒绝策略。

拒绝策略用来指示线程池在已有线程数量已达到最大值得时候该如何做,默认策略AbortPolicy,它的处理方式就是抛出RejectedExecutionException异常。我们可自己定义拒绝策略,方式就是实现RejectedExecutionHandler接口,该接口很简单,就包含一个方法:void rejectedExecution(Runnable r, ThreadPoolExecutor executor)。

以上简单概括了ThreadPoolExecutor的几个重要概念

ThreadPoolExecutor创建

当然,在使用中一般不会直接New一个ThreadPoolExecutor,Java提供了一个方便的调用类:Executors,里面提供了几种创建方法,如下:

1.ExecutorService newFixedThreadPool(int nThreads);

2.ExecutorService newCachedThreadPool()

3.ScheduledExecutorService newSingleThreadScheduledExecutor()

4.ScheduledExecutorService newScheduledThreadPool()

ThreadPoolExecutor添加任务

向ThreadPoolExecutor提交的任务,包含两种形式,一种是常见的Runnable,另一种是Callable
提交方法:

  void execute(Runnable command);  <T> Future<T> submit(Callable<T> task);

当然,这并不是全部方法,但是是最常用的。

ThreadPoolExecutor关闭

线程池的关闭有2种方式:

shutdownshutdownNow

区别:

shutdown 没有shutdownNow那么”暴力”,它先将线程池的状态设置为SHUTDOWN,将处于空闲状态的线程停掉,然后等待运行中的线程处理完任务再退出。而shutdownNow 会触发线程的中断,影响包含全部线程。这其中还有很多细节在此不展开了。


~~~ To Be Continued

原创粉丝点击