多线程是个坑,这话一点不假。最近在使用多线程异步发送邮件的时候就掉坑了。
老代码如下:
private static class SendExecutor extends Thread {
public void run() {
init();
if (null != queue) {
try {
while (true) {
EmailInfo email = queue.poll(300, TimeUnit.SECONDS);
if (null != email) {
if (log.isInfoEnabled()) {
log.info("send email , targetEmail : " + email.getTargetEmail() + " subject : " + email.getSubject());
}
if (log.isDebugEnabled()) {
log.debug("send email , targetEmail : " + email.getTargetEmail() + " subject : " + email.getSubject() + " content "
+ email.getContent());
}
sendMail(email.getContent(), email.getSubject(), email.getTargetEmail());
}
}
} catch (Exception e) {
log.error("", e);
}
}
}
}
queue采用的是LinkedBlockingQueue, 粗略的看,是否没有问题(我也是这样的)。 但代码在生产环境上出现了bug。
客户反应,邮件没有接受到. 看日志,代码也没有发现问题。最后在日志中发现了一个错误日志,才提醒了我问题出现的地方。
问题出现在try{}catch的位置在循环外,因此,如果出现异常,while将跳出,线程将完成,后续就没有消费者执行发送任务。
查看系统日志发现,因为系统中有部分老用户,老用户的邮箱地址不规范,例如,有一个用户的邮箱地址是 “1”,导致在执行sendMail()的时候,出现异常。
修改这个bug其实也很简单,将try{}catch防止在while里面就行,当然,在进入队列之前,检查邮箱是否为合格的邮箱地址很有必要.
修改后的代码如下:
private static class SendExecutor extends Thread {
public void run() {
init();
if (null != queue) {
while (true) {
try {
EmailInfo email = queue.poll(300, TimeUnit.SECONDS);
if (null != email) {
if (log.isInfoEnabled()) {
log.info("send email , targetEmail : " + email.getTargetEmail() + " subject : " + email.getSubject());
}
if (log.isDebugEnabled()) {
log.debug("send email , targetEmail : " + email.getTargetEmail() + " subject : " + email.getSubject() + " content "
+ email.getContent());
}
sendMail(email.getContent(), email.getSubject(), email.getTargetEmail());
}
} catch (Exception e) {
log.error("", e);
}
}
}
}
}