• Java mail发送邮件时卡住,没有任何异常日志(出现阻塞线程)


    问题背景

    线上有个项目是每10分钟从数据库读取需要发送的数据,通过处理后使用smtp方式发送邮件出去。发送邮件的模块偶尔会阻塞住,致使整个线程阻塞。诡异的是没有捕获到任何异常日志,程序莫名其妙的就一直卡在发送邮件的地方,不能正常结束。导致后续的执行无法继续进行。数据积压发现问题。

    问题排查

    推荐使用jstack去跟踪堆栈的信息。

    jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

    具体使用 https://www.cnblogs.com/kongzhongqijing/articles/3630264.htmlicon-default.png?t=M5H6https://www.cnblogs.com/kongzhongqijing/articles/3630264.html

    解决方案

    最后,发现是因为在发送邮件的时候没有配置超时时间,导致某些线程在发送邮件的时候阻塞掉了

    • mail.smtp.connectiontimeout:连接时间限制,单位毫秒。是关于与邮件服务器建立连接的时间长短的。默认是无限制。
    • mail.smtp.timeout:邮件接收时间限制,单位毫秒。这个是有关邮件接收时间长短。默认是无限制。
    • mail.smtp.writetimeout:邮件发送时间限制,单位毫秒。有关发送邮件时内容上传的时间长短。默认同样是无限制。

    代码片段

    1. private static final String MAILSERVER = "smtp.163.com";
    2. private static final String PROTOCOL = "smtp";
    3. public boolean send() {
    4. try {
    5. Properties props = System.getProperties();
    6. props.put("mail.host", MAILSERVER);
    7. props.put("mail.transport.protocol", PROTOCOL);
    8. // 发送邮件阻塞问题解决——设置 smtp 超时时间
    9. props.put("mail.smtp.connectiontimeout", "10000");// 设置接收超时时间
    10. props.put("mail.smtp.timeout", "10000");// 设置读取超时时间
    11. props.put("mail.smtp.writetimeout", "10000");// 设置写入超时时间
    12. Session mailSession = Session.getDefaultInstance(props, null);
    13. mailSession.setDebug(false);
    14. Message msg = new MimeMessage(mailSession);
    15. msg.setFrom(new InternetAddress(this.mail.getFrom()));
    16. if (this.mail.getTo() != null)
    17. msg.setRecipients(Message.RecipientType.TO, getInternetAddress(this.mail.getTo()));
    18. if (this.mail.getCc() != null)
    19. msg.setRecipients(Message.RecipientType.CC, getInternetAddress(this.mail.getCc()));
    20. if (this.mail.getBcc() != null)
    21. msg.setRecipients(Message.RecipientType.BCC, getInternetAddress(this.mail.getBcc()));
    22. msg.setSubject(this.mail.getSubject());
    23. MimeMultipart allPart = new MimeMultipart("mixed");
    24. MimeBodyPart content = createContent(this.mail.getContent());
    25. allPart.addBodyPart(content);
    26. if (!StringUtil.isEmpty(this.mail.getAttach())) {
    27. StringTokenizer st = new StringTokenizer(this.mail.getAttach(), ";");
    28. while (st.hasMoreTokens()) {
    29. MimeBodyPart attach = createAttachment(st.nextToken());
    30. allPart.addBodyPart(attach);
    31. }
    32. }
    33. msg.setContent(allPart);
    34. msg.setSentDate(new Date());
    35. msg.saveChanges();
    36. Transport.send(msg);
    37. return true;
    38. } catch (Exception e) {
    39. e.printStackTrace();
    40. setMessage(e.getMessage());
    41. }
    42. return false;
    43. }
    44. private static InternetAddress[] getInternetAddress(String mailAddress) {
    45. StringTokenizer st = new StringTokenizer(mailAddress, ";");
    46. int amount = 0;
    47. StringBuilder newMailAddress = new StringBuilder();
    48. while (st.hasMoreTokens()) {
    49. String tp = st.nextToken().trim();
    50. if (!newMailAddress.toString().contains(tp)) {
    51. amount++;
    52. newMailAddress.append(";").append(tp);
    53. }
    54. }
    55. InternetAddress[] address = new InternetAddress[amount];
    56. StringTokenizer st1 = new StringTokenizer(newMailAddress.toString(), ";");
    57. int i = 0;
    58. while (st1.hasMoreTokens()) {
    59. try {
    60. address[i] = new InternetAddress(st1.nextToken().trim());
    61. } catch (Exception e) {
    62. System.out.println(e.toString());
    63. e.printStackTrace();
    64. }
    65. i++;
    66. }
    67. return address;
    68. }
    69. private static MimeBodyPart createContent(String body) throws Exception {
    70. MimeBodyPart textBody = new MimeBodyPart();
    71. textBody.setContent(body, "text/html;charset=utf-8");
    72. return textBody;
    73. }
    74. private static MimeBodyPart createAttachment(String fileName) throws Exception {
    75. MimeBodyPart attachmentPart = new MimeBodyPart();
    76. FileDataSource fds = new FileDataSource(fileName);
    77. attachmentPart.setDataHandler(new DataHandler(fds));
    78. attachmentPart.setFileName(fds.getName());
    79. return attachmentPart;
    80. }
  • 相关阅读:
    vscode里面进行git提交
    数据可视化基础与应用-01-课程目标与职位分析
    97. 常用的HTTP服务压测工具
    2022年武汉市两化融合贯标补贴政策详情!
    python常用基础笔记
    Go语言开发实战课后编程题
    ​kali渗透测试环境搭建
    30个CSS选择器
    分布式场景下接口的限流、幂等、防止重复提交
    【批处理DOS-CMD命令-汇总和小结】-查看或修改文件属性(ATTRIB),查看、修改文件关联类型(assoc、ftype)
  • 原文地址:https://blog.csdn.net/gmaaa123/article/details/125417439