并发编程学习之线程池
目录
一、简介
二、线程池相关类说明
三、线程池种类
四、总结
一、简介
首先,我们先了解一下为什么要用线程池?
很多年以前,单核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. 代码如下 using System; using Sy ...
- libevent c++高并发网络编程_高并发编程学习(2)——线程通信详解
前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...
- 高并发编程学习(2)——线程通信详解
前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...
- 高并发编程基础(线程池基础)
线程池简单基础介绍: Executor: Executor是Java工具类,执行提交给它的Runnable任务.该接口提供了一种基于任务运行机制的任务提交方法,包括线程使用详细信息,时序等等.Exec ...
- Java面试系列之并发编程专题-Java线程池灵魂拷问
金三银四跳槽季即将来临,想必有些猿友已经蠢蠢欲动在做相关的准备了!在接下来的日子里,笔者将坚持写作.分享Java工程师在面试求职期间的方方面面,包括简历制作.面试场景复现.面试题解答.谈薪技巧 以及 ...
- 【JUC并发编程11】线程池
文章目录 线程池 11.1 线程池概述 11.2 线程池架构 11.3 线程池使用方式 11.4 线程池底层原则 11.5 线程池的七个参数 11.6 线程池底层工作流程 11.7 自定义线程池 线程 ...
- Java 并发编程之自定义线程池 ThreadPoolExecutor
1)定义一个任务线程 public class Task implements Runnable {private String name;Task(String name) {this.name = ...
- Java并发编程之调度线程池
调度线程池: 调度线程池是线程池类ThreadPoolExecutor的子类,复用了线程池的计算框架,主要用于解决任务在一定的时间间隔后重复执行的问题. 例子 public class Schedul ...
- 并发编程系列之线程池工厂类:Executors
前言 上节讲了讲自定义线程池,今天我们来聊聊线程池框架,在实际开发中我们还是基本使用线程框架Executor给我们提供的一些工具类,Java提供的Executor都在JUC(java.util.con ...
- 并发编程系列---【线程池七大核心参数】
一.七大核心参数 1.corePoolSize 核心线程数 2.maximumPoolSize 最大线程池参数 ...
最新文章
- python文字教程-Python
- 欧拉函数(Euler_Function)
- 华为手机充满有提醒吗_华为推出的联发科天玑手机华为nova8 SE,你会买吗?
- 云平台需要开发的底层功能
- git 修改commit_结合IDEA与命令行,解决常用git操作与特殊情况的最佳实践
- 基于MATLAB的特殊函数与画图(附图像与代码)
- Spring MVC学习(6)—Spring数据类型转换机制全解【一万字】
- 肠道微生物会导致你变胖吗?
- Navicat Premium的下载及安装
- CSS控制按钮渐变过渡效果(鼠标移入移出)
- 当前计算机硬盘容量的计量单位是GB,当前计算机硬盘容量的计量单位是GB,它相当于________字节...
- 如何在线编辑Office文档
- 普通的照片,如何在线快速制作自己的证件照
- JSP页面%@ ...%是 什么意思
- 【每日蓝桥】52、一七年省赛Java组真题“K倍区间”
- 滴滴出行打车APP-增加RFID认证、海外版、司机证件号码识别功能
- Python 通过 STMP 发送邮件(云服务器可用)
- Vue 实例之数据绑定,事件,组件,生命周期!!!
- android识别手机文件 快速扫描并优化加载速度
- Linux系统调用全过程详解
热门文章
- php标记符 编译,PHP: 编译问题 - Manual
- TrainingModel(3)
- 自动驾驶 7-1 Carla 概述 - 自动驾驶汽车模拟Carla Overview - Self-Driving Car Simulation
- 机器学习- 吴恩达Andrew Ng Week6 知识总结 Machine Learning System Design
- 猴子都能懂的数据库范式详解
- linux挂载曙光存储,曙光I1620G30获取设备的cpu、内存、存储等参数信息。
- 使用机器学习模型对大盘指数进行预测
- Scala学习数组/映射/元组
- svm出现浮点数与字符串不能计算的错误(label必须为 整形或浮点型)
- android studio for android learning (十六) support-annotations简介