目录

一、简介

二、线程池相关类说明

三、线程池种类

四、总结


一、简介

首先,我们先了解一下为什么要用线程池?

很多年以前,单核CPU的时候,多线程其实是假的,只是线程之间高速切换造成的“多线程”假象。现如今,基本上都是多核CPU电脑,多个线程各自跑在独立的CPU上,不用切换,效率比较高。

线程池的主要特点:

  • 线程可复用;
  • 控制最大并发数;
  • 管理线程;

线程池的优势:

线程池主要是控制运行的线程数量,处理过程中将任务加入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。总结主要有以下优点:

  • 降低系统消耗,通过重复利用已创建好的线程减低线程创建和销毁带来的开销;
  • 提高响应速度,当任务到达时,任务可以不需要等待线程创建就可以执行;
  • 提高线程的可管理性,线程是稀缺资源,如果无限的创建,不仅会消耗很多系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控;

二、线程池相关类说明

线程池整体架构图大概如下:

线程池的使用涉及三个比较重要的类:

【a】Executor接口:执行已提交的可运行任务的对象。该接口提供了一种将任务提交与如何运行每个任务的机制(包括线程使用、调度等细节)分离的方法。其中包含一个重要方法:

void

execute(Runnable command)

在将来的某个时候执行给定的命令

【b】ExecutorService接口

public interface ExecutorService
extends Executor

ExecutorService继承自Executor接口:用于管理终止的方法的执行程序,以及可以产生用于跟踪一个或多个异步任务进展的未来的方法。在使用完ExecutorService后,应该关闭未使用的ExecutorService,以允许回收其资源。JDK提供了两种不同的方法来关闭ExecutorService:

  • shutdown()方法:允许在终止之前执行以前提交的任务;
  • shutdownNow()方法:可以防止等待的任务启动并尝试停止当前正在执行的任务;

ExecutorService重要方法:

方法返回值类型

方法描述

boolean

awaitTermination(long timeout, TimeUnit unit)

阻塞,直到所有任务在关闭请求后完成执行,或超时发生,或当前线程被中断(以先发生的情况为准)

<T> List<Future<T>>

invokeAll(Collection<? extends Callable<T>> tasks)

执行给定的任务,返回一个结果列表,其中包含所有任务完成时的状态和结果

<T> List<Future<T>>

invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)

执行给定的任务,当所有任务完成或超时结束时,返回包含状态和结果的期货列表(以先发生的情况为准)

<T> T

invokeAny(Collection<? extends Callable<T>> tasks)

执行给定的任务,返回一个已成功完成的任务的结果(即,不抛出异常),如果有的话

<T> T

invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)

执行给定的任务,返回一个已成功完成的任务的结果(即,而不抛出异常),如果在给定超时超时之前有任何操作

boolean

isShutdown()

如果此执行程序已关闭,则返回true

boolean

isTerminated()

如果所有任务在关闭后都已完成,则返回true

void

shutdown()

启动有序关闭,在此过程中执行以前提交的任务,但不接受任何新任务

List<Runnable>

shutdownNow()

尝试停止所有正在执行的任务,停止对等待的任务的处理,并返回等待执行的任务列表

<T> Future<T>

submit(Callable<T> task)

提交一个返回值的任务以供执行,并返回一个表示该任务的未决结果的Future

Future<?>

submit(Runnable task)

提交一个可运行任务以供执行,并返回一个表示该任务的Future

<T> Future<T>

submit(Runnable task, T result)

提交一个可运行任务以供执行,并返回一个表示该任务的Future

【c】Executors工具类

public class Executors
extends Object

Executors其实是一个工具类,继承自Object基类。这个包中定义的用于Executor、ExecutorService、ScheduledExecutorService、ThreadFactory和可调用类的工厂和实用程序方法:

  • 创建并返回使用常用配置设置设置的ExecutorService;
  • 创建并返回使用常用配置设置设置的ScheduledExecutorService;
  • 创建并返回一个ThreadFactory,它将新创建的线程设置为已知状态;

Executors常用方法如下表所示:

方法返回值类型

方法描述

static ExecutorService

newCachedThreadPool()

创建一个线程池,该线程池根据需要创建新线程,但在以前构造的线程可用时将重用它们。

static ExecutorService

newCachedThreadPool(ThreadFactory threadFactory)

创建一个线程池,该线程池根据需要创建新线程,但在以前构造的线程可用时将重用它们,并在需要时使用提供的ThreadFactory创建新线程

static ExecutorService

newFixedThreadPool(int nThreads)

创建一个线程池,该线程池重用在共享无界队列上操作的固定数量的线程

static ExecutorService

newFixedThreadPool(int nThreads, ThreadFactory threadFactory)

创建一个线程池,该线程池重用在共享无界队列上操作的固定数量的线程,在需要时使用提供的ThreadFactory创建新线程

static ScheduledExecutorService

newScheduledThreadPool(int corePoolSize)

创建一个线程池,该线程池可以调度命令在给定延迟后运行,或定期执行

static ScheduledExecutorService

newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)

创建一个线程池,该线程池可以调度命令在给定延迟后运行,或定期执行

static ExecutorService

newSingleThreadExecutor()

创建一个执行程序,该执行程序使用一个工作线程在一个无界队列上操作

static ExecutorService

newSingleThreadExecutor(ThreadFactory threadFactory)

创建一个执行程序,该执行程序使用一个工作线程操作一个无界队列,并在需要时使用提供的ThreadFactory创建一个新线程

static ScheduledExecutorService

newSingleThreadScheduledExecutor()

创建一个单线程执行器,该执行器可以调度命令在给定延迟后运行,或定期执行

static ScheduledExecutorService

newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

创建一个单线程执行器,该执行器可以调度命令在给定延迟后运行,或定期执行

static ExecutorService

newWorkStealingPool()

使用所有可用的处理器作为其目标并行度级别,创建一个窃取工作的线程池

static ExecutorService

newWorkStealingPool(int parallelism)

创建一个线程池,该线程池维护足够的线程以支持给定的并行度级别,并且可以使用多个队列来减少争用

三、线程池种类

Executor主要提供了五种线程池:

  • newFixedThreadPool()方法:该方法返回一个固定数量的线程池;
  • newSingleThreadExecutor()方法:该方法返回只有一个线程的线程池;
  • newCachedThreadPool()方法:该方法返回一个可根据实际情况调整线程数量的线程池;
  • newScheduledThreadPool()方法:该方法返回一个ScheduleExecutorService对象,可以指定线程数量;
  • newSingleThreadScheduledExecutor()方法:该方法返回一个ScheduleExecutorService对象,线程数量为1;

下面通过简单的示例说明各种线程池的使用方法:

【a】 Executors.newFixedThreadPool(5): 创建固定数量的线程池

public class T14_ThreadPool {public static void main(String[] args) {/*** 创建一个固定大小为5个线程的线程池*/ExecutorService executorService = Executors.newFixedThreadPool(5);try {for (int i = 0; i < 10; i++) {executorService.execute(() -> {System.out.println(Thread.currentThread().getName() + "---使用线程--");});}} catch (Exception e) {e.printStackTrace();} finally {executorService.shutdown();}}
}

运行结果:

pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-2---使用线程--
pool-1-thread-4---使用线程--
pool-1-thread-3---使用线程--
pool-1-thread-5---使用线程--

我们发现,由于指定了线程池中只有五个线程,所以五个线程一共要完成十个任务,必然有一些线程要干多一点事情。

【b】Executors.newSingleThreadExecutor(): 创建只有一个线程的线程池

public class T14_ThreadPool {public static void main(String[] args) {/*** 创建一个只有一个线程的线程池*/ExecutorService executorService = Executors.newSingleThreadExecutor();try {for (int i = 0; i < 10; i++) {executorService.execute(() -> {System.out.println(Thread.currentThread().getName() + "---使用线程--");});}} catch (Exception e) {e.printStackTrace();} finally {executorService.shutdown();}}
}

运行结果:

pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--

我们发现,由于指定了线程池中只有一个线程,十个任务全部都由同一个线程来完成。

【c】Executors.newCachedThreadPool(): 创建动态扩充线程数量的线程池

public class T14_ThreadPool {public static void main(String[] args) {/*** 创建一个支持缓存的线程池* 可扩容*/ExecutorService executorService = Executors.newCachedThreadPool();try {for (int i = 0; i < 10; i++) {executorService.execute(() -> {System.out.println(Thread.currentThread().getName() + "---使用线程--");});}} catch (Exception e) {e.printStackTrace();} finally {executorService.shutdown();}}
}

运行结果:

pool-1-thread-1---使用线程--
pool-1-thread-2---使用线程--
pool-1-thread-9---使用线程--
pool-1-thread-8---使用线程--
pool-1-thread-7---使用线程--
pool-1-thread-10---使用线程--
pool-1-thread-6---使用线程--
pool-1-thread-5---使用线程--
pool-1-thread-4---使用线程--
pool-1-thread-3---使用线程--

我们发现,由于此类线程池可动态扩展,根据实际情况,具体会生成多少个线程我们也不能确定,所以如果需要的线程不能预估,那么此种方式需要谨慎使用。

【d】Executors.newScheduledThreadPool(10):创建支持定时调度的线程池

public class T14_ThreadPool {public static void main(String[] args) {/*** 计划任务*/ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);scheduledExecutorService.scheduleAtFixedRate(() -> System.out.println(Thread.currentThread().getName() + "---使用线程--"), 0, 1, TimeUnit.SECONDS);}
}

运行结果:

pool-1-thread-1---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-2---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-3---使用线程--
pool-1-thread-2---使用线程--
pool-1-thread-4---使用线程--
pool-1-thread-1---使用线程--
pool-1-thread-5---使用线程--
pool-1-thread-3---使用线程--
....

下面再来看一个通过ScheduledFuture.get()获取线程执行结果的示例:

public class T13_TestScheduledThreadPool {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);for (int i = 0; i < 3; i++) {ScheduledFuture<String> scheduledFuture = scheduledExecutorService.schedule(() -> {System.out.println(Thread.currentThread().getName());return UUID.randomUUID().toString();}, 1, TimeUnit.SECONDS);String s = null;try {s = scheduledFuture.get();} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}System.out.println(s);}scheduledExecutorService.shutdown();}
}

运行结果:

pool-1-thread-1
87150c0b-7353-413f-9b4e-62e1e4f64bc1
pool-1-thread-1
53d0a8ec-89f8-4076-9301-740b54fc8cfd
pool-1-thread-2
e1df93c9-73c1-45aa-a902-1679c3cf4804

可以看到,通过scheduleAtFixedRate方法可以定时执行某个任务。

/*** 计划任务* @param 任务执行的具体命令* @param 延迟首次执行的时间* @param 期间连续执行的时期* @param 单位时间单位的初始延迟和周期参数*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);

四、总结

本文主要总结线程池的一些优势、使用方法以及常用API,并结合示例说明了各种线程池的使用。下一篇文章将会总结线程池相关底层原理和自定义线程池。

并发编程学习之线程池相关推荐

  1. 多线程编程学习笔记——线程池(二)

    接上文 多线程编程学习笔记--线程池(一) 三.线程池与并行度 此示例是学习如何应用线程池实现大量的操作,及与创建大量线程进行工作的区别. 1. 代码如下 using System; using Sy ...

  2. libevent c++高并发网络编程_高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  3. 高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  4. 高并发编程基础(线程池基础)

    线程池简单基础介绍: Executor: Executor是Java工具类,执行提交给它的Runnable任务.该接口提供了一种基于任务运行机制的任务提交方法,包括线程使用详细信息,时序等等.Exec ...

  5. Java面试系列之并发编程专题-Java线程池灵魂拷问

    金三银四跳槽季即将来临,想必有些猿友已经蠢蠢欲动在做相关的准备了!在接下来的日子里,笔者将坚持写作.分享Java工程师在面试求职期间的方方面面,包括简历制作.面试场景复现.面试题解答.谈薪技巧 以及 ...

  6. 【JUC并发编程11】线程池

    文章目录 线程池 11.1 线程池概述 11.2 线程池架构 11.3 线程池使用方式 11.4 线程池底层原则 11.5 线程池的七个参数 11.6 线程池底层工作流程 11.7 自定义线程池 线程 ...

  7. Java 并发编程之自定义线程池 ThreadPoolExecutor

    1)定义一个任务线程 public class Task implements Runnable {private String name;Task(String name) {this.name = ...

  8. Java并发编程之调度线程池

    调度线程池: 调度线程池是线程池类ThreadPoolExecutor的子类,复用了线程池的计算框架,主要用于解决任务在一定的时间间隔后重复执行的问题. 例子 public class Schedul ...

  9. 并发编程系列之线程池工厂类:Executors

    前言 上节讲了讲自定义线程池,今天我们来聊聊线程池框架,在实际开发中我们还是基本使用线程框架Executor给我们提供的一些工具类,Java提供的Executor都在JUC(java.util.con ...

  10. 并发编程系列---【线程池七大核心参数】

    一.七大核心参数 1.corePoolSize                            核心线程数 2.maximumPoolSize                   最大线程池参数 ...

最新文章

  1. python文字教程-Python
  2. 欧拉函数(Euler_Function)
  3. 华为手机充满有提醒吗_华为推出的联发科天玑手机华为nova8 SE,你会买吗?
  4. 云平台需要开发的底层功能
  5. git 修改commit_结合IDEA与命令行,解决常用git操作与特殊情况的最佳实践
  6. 基于MATLAB的特殊函数与画图(附图像与代码)
  7. Spring MVC学习(6)—Spring数据类型转换机制全解【一万字】
  8. 肠道微生物会导致你变胖吗?
  9. Navicat Premium的下载及安装
  10. CSS控制按钮渐变过渡效果(鼠标移入移出)
  11. 当前计算机硬盘容量的计量单位是GB,当前计算机硬盘容量的计量单位是GB,它相当于________字节...
  12. 如何在线编辑Office文档
  13. 普通的照片,如何在线快速制作自己的证件照
  14. JSP页面%@ ...%是 什么意思
  15. 【每日蓝桥】52、一七年省赛Java组真题“K倍区间”
  16. 滴滴出行打车APP-增加RFID认证、海外版、司机证件号码识别功能
  17. Python 通过 STMP 发送邮件(云服务器可用)
  18. Vue 实例之数据绑定,事件,组件,生命周期!!!
  19. android识别手机文件 快速扫描并优化加载速度
  20. Linux系统调用全过程详解

热门文章

  1. php标记符 编译,PHP: 编译问题 - Manual
  2. TrainingModel(3)
  3. 自动驾驶 7-1 Carla 概述 - 自动驾驶汽车模拟Carla Overview - Self-Driving Car Simulation
  4. 机器学习- 吴恩达Andrew Ng Week6 知识总结 Machine Learning System Design
  5. 猴子都能懂的数据库范式详解
  6. linux挂载曙光存储,曙光I1620G30获取设备的cpu、内存、存储等参数信息。
  7. 使用机器学习模型对大盘指数进行预测
  8. Scala学习数组/映射/元组
  9. svm出现浮点数与字符串不能计算的错误(label必须为 整形或浮点型)
  10. android studio for android learning (十六) support-annotations简介