线程池

JVM 中的线程与操作系统的线程是一对一的关系,所以在 JVM 中每创建一个线程就需要调用操作系统提供的 API 创建线程,赋予资源,并且销毁线程同样也需要系统调用。

而系统调用就意味着上下文切换等开销,并且线程也是需要占用内存的,而内存也是珍贵的资源。

因此线程的创建和销毁是一个重操作,并且线程本身也占用资源。

然后你还需要知道,线程数并不是越多越好。

我们都知道线程是 CPU 调度的最小单位,在单核时代,如果是纯运算的操作是不需要多线程的,一个线程一直执行运算即可。但如果这个线程正在等待 I/O 操作,此时 CPU 就处于空闲状态,这就浪费了 CPU 的算力,因此有了多线程,在某线程等待 I/O 等操作的时候,另一个线程顶上,充分利用 CPU,提高处理效率。

CPU 的核心数有限,同时能运行的线程数有限,所以需要根据调度算法切换执行的线程,而线程的切换需要开销,比如替换寄存器的内容、高速缓存的失效等等。

<<======>>

  • Java中线程与操作系统线程是一比一的关系。
  • 线程的创建和销毁是一个“较重”的操作。
  • 多线程的主要是为了提高 CPU 的利用率。
  • 线程的切换有开销,线程数的多少需要结合 CPU核心数与 I/O 等待占比.

------------->

因为线程数太少无法充分利用 CPU ,太多的话由于上下文切换的消耗又得不偿失,所以我们需要评估系统所要承载的并发量和所执行任务的特性,得出大致需要多少个线程数才能充分利用 CPU,因此需要控制线程数量。

又因为线程的创建和销毁是一个“重”操作,所以我们需要避免线程频繁地创建与销毁,因此我们需要缓存一批线程,让它们时刻准备着执行任务。

目标已经很清晰了,弄一个池子,里面存放约定数量的线程,这就是线程池,一种池化技术。

 

注释:一般池化技术的使用方式是从池子里拿出资源,然后使用,用完了之后归还;线程池的常见实现更像是一个黑盒存在,我们设置好线程池的大小之后,直接往线程池里面丢任务,然后就不管了。线程池其实是一个典型的生产者-消费者模式。

线程池内部会有一个队列来存储我们提交的任务,而内部线程不断地从队列中索取任务来执行,这就是线程池最原始的执行机制。

线程池把任务的提交和任务的执行剥离开来,当一个任务被提交到线程池之后:

  • 如果此时线程数小于核心线程数,那么就会新起一个线程来执行当前的任务。
  • 如果此时线程数大于核心线程数,那么就会将任务塞入阻塞队列中,等待被执行。
  • 如果阻塞队列满了,并且此时线程数小于最大线程数,那么会创建新线程来执行当前任务。
  • 如果阻塞队列满了,并且此时线程数大于最大线程数,那么会采取拒绝策略。

线程池de几种状态:

  • RUNNING:能接受新任务,并处理阻塞队列中的任务
  • SHUTDOWN:不接受新任务,但是可以处理阻塞队列中的任务
  • STOP:不接受新任务,并且不处理阻塞队列中的任务,并且还打断正在运行任务的线程,就是直接撂担子不干了!
  • TIDYING:所有任务都终止,并且工作线程也为0,处于关闭之前的状态
  • TERMINATED:已关闭。

原文地址:https://www.cnblogs.com/KL2016/p/14980459.html