线上有个项目是每10分钟从数据库读取需要发送的数据,通过处理后使用smtp方式发送邮件出去。发送邮件的模块偶尔会阻塞住,致使整个线程阻塞。诡异的是没有捕获到任何异常日志,程序莫名其妙的就一直卡在发送邮件的地方,不能正常结束。导致后续的执行无法继续进行。数据积压发现问题。
推荐使用jstack去跟踪堆栈的信息。
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
最后,发现是因为在发送邮件的时候没有配置超时时间,导致某些线程在发送邮件的时候阻塞掉了
- mail.smtp.connectiontimeout:连接时间限制,单位毫秒。是关于与邮件服务器建立连接的时间长短的。默认是无限制。
- mail.smtp.timeout:邮件接收时间限制,单位毫秒。这个是有关邮件接收时间长短。默认是无限制。
- mail.smtp.writetimeout:邮件发送时间限制,单位毫秒。有关发送邮件时内容上传的时间长短。默认同样是无限制。
- private static final String MAILSERVER = "smtp.163.com";
- private static final String PROTOCOL = "smtp";
-
- public boolean send() {
-
-
- try {
- Properties props = System.getProperties();
- props.put("mail.host", MAILSERVER);
- props.put("mail.transport.protocol", PROTOCOL);
- // 发送邮件阻塞问题解决——设置 smtp 超时时间
- props.put("mail.smtp.connectiontimeout", "10000");// 设置接收超时时间
- props.put("mail.smtp.timeout", "10000");// 设置读取超时时间
- props.put("mail.smtp.writetimeout", "10000");// 设置写入超时时间
- Session mailSession = Session.getDefaultInstance(props, null);
-
- mailSession.setDebug(false);
- Message msg = new MimeMessage(mailSession);
- msg.setFrom(new InternetAddress(this.mail.getFrom()));
- if (this.mail.getTo() != null)
- msg.setRecipients(Message.RecipientType.TO, getInternetAddress(this.mail.getTo()));
- if (this.mail.getCc() != null)
- msg.setRecipients(Message.RecipientType.CC, getInternetAddress(this.mail.getCc()));
- if (this.mail.getBcc() != null)
- msg.setRecipients(Message.RecipientType.BCC, getInternetAddress(this.mail.getBcc()));
- msg.setSubject(this.mail.getSubject());
-
- MimeMultipart allPart = new MimeMultipart("mixed");
-
- MimeBodyPart content = createContent(this.mail.getContent());
- allPart.addBodyPart(content);
-
- if (!StringUtil.isEmpty(this.mail.getAttach())) {
- StringTokenizer st = new StringTokenizer(this.mail.getAttach(), ";");
- while (st.hasMoreTokens()) {
- MimeBodyPart attach = createAttachment(st.nextToken());
- allPart.addBodyPart(attach);
- }
- }
-
- msg.setContent(allPart);
- msg.setSentDate(new Date());
- msg.saveChanges();
- Transport.send(msg);
-
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- setMessage(e.getMessage());
- }
- return false;
- }
-
- private static InternetAddress[] getInternetAddress(String mailAddress) {
- StringTokenizer st = new StringTokenizer(mailAddress, ";");
- int amount = 0;
- StringBuilder newMailAddress = new StringBuilder();
- while (st.hasMoreTokens()) {
- String tp = st.nextToken().trim();
- if (!newMailAddress.toString().contains(tp)) {
- amount++;
- newMailAddress.append(";").append(tp);
- }
-
- }
-
- InternetAddress[] address = new InternetAddress[amount];
- StringTokenizer st1 = new StringTokenizer(newMailAddress.toString(), ";");
- int i = 0;
- while (st1.hasMoreTokens()) {
- try {
- address[i] = new InternetAddress(st1.nextToken().trim());
- } catch (Exception e) {
- System.out.println(e.toString());
- e.printStackTrace();
- }
- i++;
- }
-
- return address;
- }
-
- private static MimeBodyPart createContent(String body) throws Exception {
- MimeBodyPart textBody = new MimeBodyPart();
- textBody.setContent(body, "text/html;charset=utf-8");
- return textBody;
- }
-
- private static MimeBodyPart createAttachment(String fileName) throws Exception {
- MimeBodyPart attachmentPart = new MimeBodyPart();
- FileDataSource fds = new FileDataSource(fileName);
- attachmentPart.setDataHandler(new DataHandler(fds));
- attachmentPart.setFileName(fds.getName());
- return attachmentPart;
- }