线程池的一些知识点回顾

对线程池的一些理解

  1. 线程池是对线程的管理和调度,我们自己当然也可以去新建线程去处理并发操作,但是线程池提供了很好的解决线程之间调度,管理的能力,这些能力可能比我们自己去实现更优。
  2. 创建线程池有两种方式(本质上是一种),如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //通过Executors封装好的线程池创建方法去创建
    Executors.newSingleThreadExecutor();
    Executors.newFixedThreadPool(10);

    //使用ThreadPoolExecutor来创建,其实上一种本质上也是调用这个来创建线程池的(阿里规范推荐)
    ExecutorService executors = new ThreadPoolExecutor(1,
    1,
    0L,
    TimeUnit.MILLISECONDS,
    new ArrayBlockingQueue<>(1),
    new ThreadPoolExecutor.DiscardPolicy());
    //其中参数1,为核心线程数;2,最大线程数;3,线程存活时间;4,线程的阻塞队列;5,线程(任务)熔断机制
  3. 基于第二点解释这些参数的意义

  • a, 核心线程数是线程池初始化就会创建的线程,并且该线程不会被回收;
  • b, 最大线程数是线程池中允许存在的最大线程数量;
  • c, 线程存活时间指的是当非核心线程在处理完任务不再使用后多久被线程池回收;
  • d, 线程阻塞队列是任务队列,线程处理的任务会按照队列的特点存在队列中;
  • e, 线程熔断机制是当线程处理不过来任务时,应该做一些什么策略。
  1. 线程池运行的流程
  • 线程池刚创建的时候,里面没有一个线程,任务队列是做为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
  • 当调用execute()方法添加一个一个任务时,线程池会做几个判断
    • a,如果正在运行的线程数量小于核心线程数,则马上创建线程执行这个任务
    • b,如果正在运行的线程数量大于或等于最大线程数,则把任务放入队列中
    • c,如果这时候队列满了,运行的线程数小于最大线程数,则创建线程立马执行这个任务
    • d,如果队列满了,运行的线程数大于等于最大线程数,则执行线程熔断机制
  • 当一个线程完成任务时,它会从队列中取下一个任务来执行
  • 当一个线程没有任务执行,超过线程存活时间时,线程池会判断,如果当前运行线程大于核心线程数,那么这个线程就会被回收。所以最终线程池的线程数量会维持为核心线程的数量。

这样的过程说明,并不是先加入任务就一定先执行,看下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ExecutorService executors = new ThreadPoolExecutor(3,
6,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(10),
new ThreadPoolExecutor.DiscardPolicy());
//ThreadTest01 test01 = new ThreadTest01();
for (int i = 1; i < 21; i++) {
int taskId = i;
Runnable task = () -> {
try {
System.out.println("thread-" + Thread.currentThread().getName() + " is saving data:" + taskId);
/*模拟存储数据耗时*/
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
executors.execute(task);
}
/*运行结果:首先核心线程为3所以立马执行任务1,2,3;然后任务4到13被放入到队列中,14,15,16又会被新创建的3个线程(最大为6)执行,
再增加任务17到20时由于当前已经有6个线程在处理任务了,所以17到20的任务由于ThreadPoolExecutor.DiscardPolicy()策略会被丢弃。
然后6个线程又会依次从队列冲取出4到13任务去执行。*/

线程池中几种队列的理解

  1. SynchronousQueue
    synchronousQueue本身没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素。
  2. LinkedBlockingQueue
  3. ArrayBlockingQueue