Java线程池的这几个大坑,你踩过几个?

news2024/9/24 9:27:32

首先看一个简单的例子:代码可能会抛出空指针异常,但这个异常就会被吞掉。

图片

要优雅解决问题,可以为线程池设置一个全局的异常处理器,使用自定义线程工厂来设置!

 

java

public class CustomThreadFactory implements ThreadFactory {
private final ThreadFactory defaultFactory = Executors.defaultThreadFactory();

@Override
public Thread newThread(Runnable r) {
Thread thread = defaultFactory.newThread(r);

// 设置全局异常处理器
thread.setUncaughtExceptionHandler((t, e) -> {
System.err.println("Thread " + t.getName() + " threw exception: " + e.getMessage());
});
return thread;
}

public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2, new CustomThreadFactory());
// 提交任务到线程池
executorService.execute(() -> {
throw new NullPointerException("Test Exception");
});
// 关闭线程池
executorService.shutdown();
}
}

拒绝策略设置错误导致接口超时!

如果没有正确设置拒绝策略,可能会导致接口超时或服务中断。

 

java

public class RejectionPolicyExample {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(
1, // 核心线程数
1, // 最大线程数
0L, // 空闲线程存活时间
TimeUnit.MILLISECONDS, // 存活时间单位
new LinkedBlockingQueue<>(1), // 任务队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.AbortPolicy() // 默认拒绝策略
);

// 提交三个任务到线程池,第三个任务将被拒绝
for (int i = 0; i < 3; i++) {
executorService.execute(() -> {
try {
Thread.sleep(1000); // 模拟任务执行
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed task");
});
}

// 关闭线程池
executorService.shutdown();
}
}

合适的拒绝策略如CallerRunsPolicy可以使任务在调用者线程中执行,从而避免任务丢失。

图片

 

java

public class CallerRunsPolicyExample {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(
1, // 核心线程数
1, // 最大线程数
0L, // 空闲线程存活时间
TimeUnit.MILLISECONDS, // 存活时间单位
new LinkedBlockingQueue<>(1), // 任务队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 调用者运行策略
);

// 提交三个任务到线程池,第三个任务将在调用者线程中执行
for (int i = 0; i < 3; i++) {
executorService.execute(() -> {
try {
Thread.sleep(1000); // 模拟任务执行
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed task");
});
}

// 关闭线程池
executorService.shutdown();
}
}

重复创建线程池导致内存溢出

重复创建线程池会导致系统资源浪费,甚至引发内存溢出。

 

java

public class DuplicateThreadPoolExample {
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
ExecutorService executorService = Executors.newFixedThreadPool(10);

// 提交任务到线程池
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + " executed task");
});

// 关闭线程池
executorService.shutdown();
}
}
}

那当然我们整个应用中只使用一个线程池实例。

 

java

public class SingletonThreadPoolExample {
// 单例线程池
private static final ExecutorService executorService = Executors.newFixedThreadPool(10);

public static ExecutorService getExecutorService() {
return executorService;
}

public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
// 使用单例线程池提交任务
getExecutorService().execute(() -> {
System.out.println(Thread.currentThread().getName() + " executed task");
});
}

// 关闭线程池
getExecutorService().shutdown();
}
}

共用线程池执行不同任务

在同一个线程池中执行不同性质的任务,可能会导致任务相互影响,进而降低系统效率。例如,CPU密集型IO密集型任务混用同一线程池,效率会大打折扣。

 

java

public class MixedTasksExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 提交CPU密集型任务
executorService.execute(() -> {
for (int i = 0; i < 1000000; i++) {} // 模拟CPU密集型任务
System.out.println(Thread.currentThread().getName() + " executed CPU-intensive task");
});
// 提交IO密集型任务
executorService.execute(() -> {
try {
Thread.sleep(2000); // 模拟IO密集型任务
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed IO-intensive task");
});
// 关闭线程池
executorService.shutdown();
}
}

解决方案:

为不同任务分配独立的线程池,确保任务执行的高效性。

 

java

public class SeparateTasksExample {
// CPU密集型任务的线程池
private static final ExecutorService cpuIntensivePool = Executors.newFixedThreadPool(5);
// IO密集型任务的线程池
private static final ExecutorService ioIntensivePool = Executors.newFixedThreadPool(5);

public static void main(String[] args) {
// 提交CPU密集型任务
cpuIntensivePool.execute(() -> {
for (int i = 0; i < 1000000; i++) {} // 模拟CPU密集型任务
System.out.println(Thread.currentThread().getName() + " executed CPU-intensive task");
});

// 提交IO密集型任务
ioIntensivePool.execute(() -> {
try {
Thread.sleep(2000); // 模拟IO密集型任务
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " executed IO-intensive task");
});

// 关闭线程池
cpuIntensivePool.shutdown();
ioIntensivePool.shutdown();
}
}

ThreadLocal与线程池的冲突

因为线程池中的线程是复用的,ThreadLocal中的变量可能会被其他任务不小心修改未及时清理

 

java

public class ThreadLocalIssueExample {
private static final ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);

public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);

// 提交任务到线程池
for (int i = 0; i < 5; i++) {
executorService.execute(() -> {
int value = threadLocal.get();
System.out.println(Thread.currentThread().getName() + " initial value: " + value);
threadLocal.set(value + 1);
System.out.println(Thread.currentThread().getName() + " updated value: " + threadLocal.get());
});
}

// 关闭线程池
executorService.shutdown();
}
}

那当然在任务执行完毕后,及时清理ThreadLocal变量

public class ThreadLocalSolutionExample {
    private static final ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        
        // 提交任务到线程池
        for (int i = 0; i < 5; i++) {
            executorService.execute(() -> {
                try {
                    int value = threadLocal.get();
                    System.out.println(Thread.currentThread().getName() + " initial value: " + value);
                    threadLocal.set(value + 1);
                    System.out.println(Thread.currentThread().getName() + " updated value: " + threadLocal.get());
                } finally {
                    // 任务完成后清理ThreadLocal变量
                    threadLocal.remove();
                }
            });
        }
        
        // 关闭线程池
        executorService.shutdown();
    }
}

最后说一句(求关注!别白嫖!)

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1989568.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CTFHUB-web-RCE-综合过滤练习

开启题目 查看网页源代码发现这次网页对 | 、 && 、 || 、 \ 、 / 、; &#xff0c;都进行了过滤处理 发现换行符 %0a 和回车符 %0d 可以进行测试&#xff0c;在 URL 后面拼接访问 127.0.0.1%0als 用 ls flag_is_here 查看 flag 文件中的内容&#xff0c;发现回显为空…

11-电阻 电容元件的创建

1. 2.格点设置 3.当设置完线条的时候&#xff0c;格点重新设置回100mil 4.更改管脚长度&#xff0c;宽度

vscode安装与配置本地c/c++编译调试环境

目录 &#xff08;1&#xff09;安装vscode和常用插件 1.下载安装vscode 2.安装常用插件 &#xff08;2&#xff09;本地安装和配置编译器 1.安装编译器 2.vscode配置编译器 第1种&#xff1a;全局配置 第2种&#xff1a;为当前项目个性化配置 &#xff08;3&#xff…

海量数据处理商用短链接生成器平台 - 9

第二十六章 短链服务-冗余双写架构删除和更新消费者开发实战 第1集 冗余双写架构-更新短链消费者开发实战 简介&#xff1a; 短链服务-更新短链-消费者开发实战 具体步骤见代码 第2集 冗余双写架构-更新短链消费者链路测试 简介&#xff1a; 冗余双写架构-更新短链消费者链…

从TiDB迁移到OceanBase的实践分享

本文来自OceanBase热心用户的分享 近期&#xff0c;我们计划将业务数据库从TiDB迁移到OceanBase&#xff0c;但面临的一个主要挑战是如何更平滑的完成这一迁移过程。经过研究&#xff0c;了解到OceanBase提供的OMS数据迁移工具能够支持从TiDB到OceanBase的迁移&#xff0c;并且…

使用snap安装docker配置阿里云镜像加速

使用snap安装docker非常的简单&#xff0c;一条命令即可 snap install docker 但是通过这个命令安装的docker, 配置阿里云镜像跟常规安装的配置起来不太一样, 下面讲一下配置流程 修改docker配置文件/var/snap/docker/current/config/daemon.json 这个文件应该是已经创建好…

13-按键的元件模型创建

1.画线的时候&#xff0c;栅格切为10mil 2.放置管脚的时候&#xff0c;栅格切为100mil

贝叶斯网络介绍与求解方法

贝叶斯网络综述 1. 引言2. 贝叶斯网络原理介绍3. 求解贝叶斯网络的各种方法3.1 精确推理算法3.2 近似推理算法3.3 学习贝叶斯网络的结构和参数3.3.1 MMPC&#xff08;Max-Min Parents and Children&#xff09;3.3.2 MMHC&#xff08;Max-Min Hill-Climbing&#xff09;3.3.3 I…

论文阅读报告: 在时间双向图上查询基于时间的的密集子图 | ICDE 2024

摘要 本文提出了一个新的模型&#xff08;α, β, T&#xff09;-core&#xff0c;用于在时间双向图上寻找凝聚子图。时间双向图中&#xff0c;不同实体之间的关系随着时间的推移而变化。为了提高查询效率&#xff0c;本文提出了顶点分区和时间分区的历史索引&#xff08;VH-I…

windows docker容器部署前端项目

一、介绍 Docker 是一个开源的平台&#xff0c;旨在简化应用程序的开发、部署和运行。它通过使用容器&#xff08;containers&#xff09;来实现这一点。容器是一种轻量级、可移植的虚拟化方式&#xff0c;可以在不同的环境中一致地运行软件。 Docker 的主要作用和优点包括&a…

C语言 ——— 学习、使用memcpy函数 并模拟实现

目录 memcpy函数的功能 学习memcpy函数​编辑 使用memcpy函数 模拟实现memcpy函数 memcpy函数的功能 memcpy函数是内存拷贝函数&#xff0c;用于把任意类型的数据的内存拷贝到另一个同类型的数据上 学习memcpy函数 函数的参数&#xff1a; void* destination&#xff1…

C++基础编程的学习2

has-a&#xff08;组合关系&#xff09; 在C中&#xff0c;has-a关系是一种对象之间的组合关系&#xff0c;表示一个类的对象包含另一个类的对象作为其成员。 前向引用说明 在全局命名作用域中声明函数&#xff0c;可以避免递归调用时的函数重名问题。前向声明允许我们声明一…

使用Pinata在IPFS上存储NFT图片的实践

文章目录 前言一、什么是IPFS&#xff1f;二、为什么NFT需要IPFS&#xff1f;三、 Pinata&#xff1a;IPFS上的存储解决方案四、 实践&#xff1a;使用Pinata存储NFT图片1. 注册2. 获取API密钥与网关3. 上传图片到IPFS 总结 前言 随着区块链技术的快速发展&#xff0c;NFT&…

【iOS】OC关键字总结及底层原理(下)

目录 weak实现原理objc_initWeak()objc_storeWeak()weak_register_no_lock()weak_entry_for_referent()dealloc关于弱引用的处理weak相关问题 __autoreleasing关键字自动释放池__autoreleasing修饰变量 weak实现原理 weak弱引用指针会存储在SideTable里的weak弱引用表里面&…

实验室冷冻干燥机的安装与调试步骤

实验室冷冻干燥机是一种重要的科研设备&#xff0c;广泛应用于生物、化学、食品科学等领域。正确安装与调试冷冻干燥机&#xff0c;不仅能确保设备的正常运行&#xff0c;还能延长其使用寿命。本文将详细介绍实验室冷冻干燥机的安装与调试步骤&#xff0c;帮助用户顺利完成设备…

Java中等题-最大子数组和(力扣)

给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#xff1a;…

SSM城市垃圾分类管理系统-计算机毕业设计源码44582

摘 要 在当前全球环境问题日益突出的背景下&#xff0c;城市垃圾分类成为推动可持续发展和环境保护的重要举措之一。然而&#xff0c;传统的垃圾处理方式存在效率低下、资源浪费和环境污染等问题。因此&#xff0c;开发一个基于Java编程语言、MySQL数据库和HTML前端技术的高效…

vue()

目录 首先我们回顾一下之前学的东西 入门&#xff1a; v-bind 绑定属性用法 ​编辑 v-if 用法 v-for v-on v-model&#xff1a;双向绑定 组件&#xff1a; 全局组件&#xff1a; 局部组件&#xff1a; vue生命周期&#xff1a;&#xff08;这里让我研究研究&…

C++ 函数模板和类模板

参考视频&#xff1a;C类模板_哔哩哔哩_bilibili 遗留问题&#xff1a;编译器怎么处理函数模板和类模板 目录 一、为什么会有函数模版&#xff1f;函数模板是为了解决什么问题&#xff1f; 二、函数模板的概念 三、函数模版的使用 四、函数模板的特化 五、类模板的概念 …

24/8/7 算法笔记 支持向量机回归问题天猫双十一

import numpy as np from sklearn.svm import SVR import matplotlib.pyplot as plt X np.linspace(0,2*np.pi,50).reshape(-1,1) y np.sin(X) plt.scatter(X,y) 建模 线性核函数 svr SVR(kernel linear) svr.fit(X,y.ravel())#变成一维y_ svr.predict(X) plt.scatter(…