线程池的基本使用
时间:2022-07-27
本文章向大家介绍线程池的基本使用,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
线程池作用
借由《Java并发编程的艺术》
- 降低资源消耗。通过重复利用已经创建的线程,能够降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要等待线程的创建就能立即执行。
- 提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
ThreadPoolExecutor类
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
...
}
ThreadPoolExecutor构造
ThreadPoolExecutor
类的构造参数:
-
corePoolSize
:核心线程数量,初始化就创建的线程,没有任务也不会被关闭的线程。也会有例外,如:allowCoreThreadTimeOut
设置为true
时,会被关闭。 -
maximumPoolSize
:最大线程数量。 -
keepAliveTime
:空闲线程的存活时间,超时后线程会被关闭,核心线程除外。 -
unit
:空闲时间单位,一般使用TimeUnit
枚举 -
workQueue
:工作队列,当所有线程都被占用后,新的任务就会被放在工作队列中。 -
threadFactory
:线程工厂。 -
handler
:饱和策略,用于线程池中没有空闲线程可以使用且工作列也处于饱和状态时执行的拒绝策略。
常用的拒绝策略
-
AbortPolicy
:抛出RejectedExecutionException
异常拒绝新的任务处理,默认拒绝策略。 -
CallerRunsPolicy
:如果程序关闭,会丢掉任务。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度,但会造成延迟。如果项目可以承受延迟且不能丢弃任何一个任务请求,可以使用此策略。 -
DiscardPolicy
:不处理新任务,直接丢掉。 -
DiscardOldestPolicy
:丢失最早的未处理的任务。
ThreadPoolExecutor线程状态
-
RUNNING
:接收新的任务和处理队列中的任务 -
SHUTDOWN
:不能新增任务,但是会继续处理已经添加的任务 -
STOP
:不能新增任务,不会继续处理已经添加任务 -
TIDYING
:所有的任务已经被终止,工作线程为0 -
TERMINATED
:terminated()方法执行完成
创建线程池
创建Runnable接口实现类
public class MyThread implements Runnable {
private String taskName;
public MyThread(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
String threadName = Thread.currentThread().getName();
System.out.println("线程 " + threadName + " 开始执行:" + taskName);
Thread.sleep(3000);
System.out.println("线程 " + threadName + " 开始执行:" + taskName);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "MyThread{" +
"taskName='" + taskName + ''' +
'}';
}
}
使用ThreadPoolExecutor创建
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
// 核心线程数
5,
// 最大线程数
10,
// 等待时间
100,
// 等待时间单位 秒
TimeUnit.SECONDS,
// 任务队列 容量100
new ArrayBlockingQueue<>(100),
// 饱和策略
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任务" + i);
executor.execute(myThread);
}
executor.shutdown();
}
几种常见的线程池
固定线程池(FixThreadPool)
线程池中的固定数量线程可以重复使用
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
创建方法:
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任务" + i);
executor.execute(myThread);
}
- 当前运行的线程数小于
coreSize
的时候,有新任务就创建线程来执行。 - 当前运行的线程数等于
coreSize
的时候,有新任务将会追加到LinkedBlockingQueue队列中。 - 线程池中的线程执行完后,会循环从LinkedBlockingQueue中获取任务执行。
需要注意的是,LinkedBlockingQueue是一个无界队列,它的容量为:
Integer.MAX_VALUE
,也就是说,当所有线程被占用后,新的任务将会无限堆加到这个队列中,如果任务较多,可能会出现OOM现象。
单一线程池(SingleThreadExecutor)
只有一个线程,空闲也不会被关闭。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
创建方法:
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任务" + i);
executor.execute(myThread);
}
缓存线程池(CachedThreadPool)
线程数量为
Integer.MAX_VALUE
,空闲线程会被临时缓存60s,没有任务分配会关闭。如果提交任务速度过快,也一样可能会出现OOM现象。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
创建方法:
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 1; i <= 10; i++) {
MyThread myThread = new MyThread("任务" + i);
executor.execute(myThread);
}
原文发布在:传送门
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Zabbix MTR 链路质量检测 主备链路监控
- R语言入门之t检验(t test)
- R语言入门之饼图
- 加速Spark编译
- 自定义方便kubectl中pods的管理
- R语言入门之切尾均值(trimmed mean)与绝对中位差(median absolute deviation,mad)
- 盘一盘 Python 特别篇 20 - SciPy 稀疏矩阵
- Spark 3.0.0-SNAPSHOT Access Kerberized HDFS
- Spark Nightly Builds
- R语言入门之基本统计量
- K8S 生态周报| Istio 已修复导致 Pod 崩溃的 bug
- Spark Kubernetes 的源码分析系列 - submit
- 如何交互可视化 Roam Research 局部笔记网络?
- Spark Kubernetes 的源码分析系列 - features
- Spark Kubernetes 的源码分析系列 - scheduler