SocketInputStream.socketRead0引起线程池提交任务后,futureTask.get超时

本文主要是介绍SocketInputStream.socketRead0引起线程池提交任务后,futureTask.get超时,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 1. 现象
    • 2. 结论
    • 3. 相关代码
    • 4. 查看堆栈:
    • 5. 查看submitCall
      • 5.1 ThreadPoolExecutor#execute最终调用了 RunnableFuture#run方法
      • 5.2 从代码层面判断 futureTask.get超时只影响了业务线程(调用futureTask.get的线程),不影响工作线程。
      • 5.3 future.get
        • 5.3.1 测试future.get并不能打断线程池的线程。
    • 6. 查看工作线程为何阻塞
      • 6.1 修复
    • 7. 相关资料

1. 现象

线上发短信、邮箱验证码 的时候超时

在这里插入图片描述

2. 结论

  1. SocketInputStream.socketRead0导致线程阻塞,阻塞后占用了线程池的线程。多次阻塞后最终占用了全部的core线程。新提交的任务只能入队,没有线程来处理。
    由于 socket.read占用了corePoolSize 个 线程池的工作线程worker.thread , 这里一共有10个,全都阻塞了。

    而execute提交一个runnable的时候, 在达到corePoolSize后, 会将其放入workQueue中。直到workQueue满。

    新的任务只能入队(enQueue),不能被消费。

    所以 futureTask.get 一直超时。

  2. futureTask.get(timeout,timeunit)不会导致线程池的工作线程异常。工作线程会继续执行。

3. 相关代码

sendVcWorkerThreadPool是ThreadPoolExecutor的子类WorkerThreadPool
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
WorkerThreadPool
这里workQueue本身是一个优先队列,这里会无限扩容
ps:由于无限扩容, 这里maxinumPoolSize是无效的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

先查找相关调用链的底层日志,发现根本没有调用底层方法。

而其他应用能调用到该底层,一直在输出日志,说明是execute本身有问题。

4. 查看堆栈:

搜索AsyncWorker(ps:自定义的线程池一定要重命名,找问题的时候方便),发现该线程池的10个core线程都处于runnable,且所有线程都在

sendEmail

在这里插入图片描述

5. 查看submitCall

虽然future.get有超时,但是这只能保证业务线程不阻塞。
future.get并不能打断线程池的线程。
在这里插入图片描述
这里的sendVcWorkerThreadPool#submitCall与ThreadPoolExecutor
ThreadPoolExecutor#submit类似
在这里插入图片描述
由于继承ThreadPoolExecutor,所以调用了ThreadPoolExecutor的execute
在这里插入图片描述

5.1 ThreadPoolExecutor#execute最终调用了 RunnableFuture#run方法

  • 调用链
    addWorker()->w.start()->treahd.run()->Worker.runWorker(Worker w)->task.run();

  • task即RunnableFuture ,newTaskFor创建了子类FutureTask

因此 查看FutureTask的run方法

  • FutureTask是对Callable的一层封装。

  • 超时只影响了业务线程(调用futureTask.get的线程),不影响工作线程。

5.2 从代码层面判断 futureTask.get超时只影响了业务线程(调用futureTask.get的线程),不影响工作线程。

FutureTask.run
在这里插入图片描述

运行完毕,设置结果
此时可以使用future.get出结果
在这里插入图片描述

这里让【因为future.get,调用park方法使得等待】的线程 恢复。
在这里插入图片描述

5.3 future.get

在这里插入图片描述

死循环检测是否完成, 超时后,直接return 当前state

Unsafe.park()本地方法休眠当前线程, HotSpot在Linux中中通过调用pthread_mutex_lock函数把线程交给系统内核进行阻塞。
在这里插入图片描述
休眠
在这里插入图片描述

检测的时候,先将当前线程添加到waitNode

在这里插入图片描述

5.3.1 测试future.get并不能打断线程池的线程。

在这里插入图片描述

6. 查看工作线程为何阻塞

虽然已经证明了futureTask.get超时后不会打断线程池的worker.thread,还是需要查看工作线程为何阻塞。
再回顾一下堆栈

在这里插入图片描述
execute的调用链是addWorker()->w.start()->treahd.run()->Worker.runWorker(Worker w)->task.run();
而FutureTask是对Callable的一层封装。

本身是SendEmailCall本身是一个Callable

我们只需要查看SendEmailCall的call方法为何一直在运行。

在这里插入图片描述
transport.connect
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

阻塞到readLine

在这里插入图片描述
到这里就很明显了, 是socket的inputStream调用read的时候阻塞。

在这里插入图片描述

socket是可以设置timeout的。

查找timeout的设置
在这里插入图片描述
getSocket
在这里插入图片描述

to为read超时时间,
cto为连接超时时间
如果不设置则都为永久

在这里插入图片描述

而创建的时候,没有设置timeout
到此就明白了, 设置timeout即可。
在这里插入图片描述

6.1 修复

props.put("mail.smtp.connectiontimeout", "3000");
props.put("mail.smtp.timeout", "3000");

在这里插入图片描述
在这里插入图片描述

debug测试
在这里插入图片描述

修改后

在这里插入图片描述

修改为超短时间 会报错。
在这里插入图片描述

7. 相关资料

线程池中的线程何时死亡?
SocketInputStream.socketRead0引起线程池提交任务后,futureTask.get超时
socket连接代理socketRead0(Native Method) 线程阻塞处理

这篇关于SocketInputStream.socketRead0引起线程池提交任务后,futureTask.get超时的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/858495

相关文章

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

Spring定时任务之fixedRateString的实现示例

《Spring定时任务之fixedRateString的实现示例》本文主要介绍了Spring定时任务之fixedRateString的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录从毫秒到 Duration:为何要改变?核心:Java.time.Duration.parse

Oracle Scheduler任务故障诊断方法实战指南

《OracleScheduler任务故障诊断方法实战指南》Oracle数据库作为企业级应用中最常用的关系型数据库管理系统之一,偶尔会遇到各种故障和问题,:本文主要介绍OracleSchedul... 目录前言一、故障场景:当定时任务突然“消失”二、基础环境诊断:搭建“全局视角”1. 数据库实例与PDB状态2

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

504 Gateway Timeout网关超时的根源及完美解决方法

《504GatewayTimeout网关超时的根源及完美解决方法》在日常开发和运维过程中,504GatewayTimeout错误是常见的网络问题之一,尤其是在使用反向代理(如Nginx)或... 目录引言为什么会出现 504 错误?1. 探索 504 Gateway Timeout 错误的根源 1.1 后端