--先用文字分析,有条件的话配图

1.问什么需要线程池

考虑下面场景:加入我们通过restful方式对接一个系统A。每次想要调用A的服务的时候都会创建一个线程发起一个请求。当获得回应后,关闭该线程。

上面的逻辑没有问题。但是当我们需要频繁调用系统A的服务时,就会频繁的创建线程和关闭线程。这有什么问题呢?

创建线程和回收线程都会占用系统资源(具体什么资源,后面需要补充),大量创建回收线程都会增加系统负担。降低系统性能。

因此,为了提高系统性能,我们提前创建一些线程,这些线程由线程池管理,使用的时候就从线程池里选一个,使用完毕就归还给线程池。当然创建线程池肯定是会占用一点内存空间。暂且忽略不计。

这里就有个问题:如果让我们自己设计一个线程池该如何设计与使用呢?通过回答我们自己的问题,就会发现线程池原理就是我们解决问题的思路。

1.假如我们的线程池里有100个线程。该如何分配呢?

答:来一个请求,分配一个线程,用完归还  (简单粗暴,貌似可以解决问题)

2.假如同同时来了200个请求,如何分配线程呢?

答:总不能拒绝提供服务吧。为了提高我们的服务质量,我们还是需要处理这些请求的。但是又没有可用的线程去处理?该怎么办呢?这个时候就需要把请求保存下来(如:队列),等有可用线程时就让线程从队列里取出一个请求进行处理。

问题2的回答就已经将线程池的大致原理给确定下来了。就是利用队列保存不能处理的请求,当有可用线程时再处理队列里的请求。

3.假如我的线程池里有1000个线程,可是现在请求很少,大量的线程是不是浪费掉了?

这时可以限制总是存活的线程数,比如20。当同时接收到的请求大于20时再创建新的线程。这也是线程池里会定义一个核心线程数。

4.上面的解决方案又要解决这样的问题:

比如:最大存活线程数设置为20,但是现在来了21个请求。多出来的这个请求是放在等待队列里,还是创建一个新的线程去处理呢?比较合理的放到等待队列里。若是创建一个线程来解决,那么,只有同时来了10000个请求时才会使用等待队列,并不能解决3中的问题。因此最好的方法就是先将多出来的请求放到等待队列里。

接下来分析:现在创建了30个线程,但是一段时间内来的请求都小于20个,这个时候就要回收多出来的线程。

5.回答完4中的问题后就有下面的流程:

1.设置最大存活线程数为20,当来的请求大于20个时,将多出的请求放到请求队列里,当请求队列满了,再创建新的线程。

2.这是请求数变小,回收多余的线程

3.请求数超过1000,同时等待队列里也满了,抛出异常

盗用一张图https://www.jianshu.com/p/87bff5cc8d8c,下面的图很清晰的说明了线程池的工作流程。

同时也将线程池配置参数列一下:

corePoolSize

线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。

maximumPoolSize

线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSize;

keepAliveTime

线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间;默认情况下,该参数只在线程数大于corePoolSize时才有用;

unit

keepAliveTime的单位;

workQueue

用来保存等待被执行的任务的阻塞队列,且任务必须实现Runable接口,在JDK中提供了如下阻塞队列:
1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
2、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene;
3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene;
4、priorityBlockingQuene:具有优先级的无界阻塞队列;

创建方式:

Executors.newFixedThreadPool(10)

 

 

android ThreadPoolExecutor 创建线程名的线程池_阻塞队列