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

相关文章

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J

异步线程traceId如何实现传递

《异步线程traceId如何实现传递》文章介绍了如何在异步请求中传递traceId,通过重写ThreadPoolTaskExecutor的方法和实现TaskDecorator接口来增强线程池,确保异步... 目录前言重写ThreadPoolTaskExecutor中方法线程池增强总结前言在日常问题排查中,

Redis 多规则限流和防重复提交方案实现小结

《Redis多规则限流和防重复提交方案实现小结》本文主要介绍了Redis多规则限流和防重复提交方案实现小结,包括使用String结构和Zset结构来记录用户IP的访问次数,具有一定的参考价值,感兴趣... 目录一:使用 String 结构记录固定时间段内某用户 IP 访问某接口的次数二:使用 Zset 进行

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行... 目录前言什么是 ShedLock?ShedLock 的工作原理:定时任务重复执行China编程的问题使用 Shed

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Java CompletableFuture如何实现超时功能

《JavaCompletableFuture如何实现超时功能》:本文主要介绍实现超时功能的基本思路以及CompletableFuture(之后简称CF)是如何通过代码实现超时功能的,需要的... 目录基本思路CompletableFuture 的实现1. 基本实现流程2. 静态条件分析3. 内存泄露 bug

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Python Invoke自动化任务库的使用

《PythonInvoke自动化任务库的使用》Invoke是一个强大的Python库,用于编写自动化脚本,本文就来介绍一下PythonInvoke自动化任务库的使用,具有一定的参考价值,感兴趣的可以... 目录什么是 Invoke?如何安装 Invoke?Invoke 基础1. 运行测试2. 构建文档3.