下面的这个方法是发邮件的抽象出来的一个公用方法:
String[] to 表示收件人列表;
subject 邮件主题;
templateName 邮件末班,用velocity写的,
Map params 参数,用来填充velocity中的某些字段取值的
public void sendHtmlWithTemplate(String[] to, String subject, String templateName, Map<String, Object> params) {
final MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
final MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
messageHelper.setFrom(simpleMailMessage.getFrom());
if (ENV_ONLINE.equals(environment)) {
messageHelper.setTo(to);
messageHelper.setSubject(subject);
} else {
messageHelper.setTo(adminEmail);
messageHelper.setSubject(subject + Arrays.asList(to));
}
messageHelper.setSentDate(new Date());
final String content = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, templateName, "UTF-8",
params);
final String[] logTo = to;
messageHelper.setText(content, true);
new Thread() {
@Override
public void run() {
mailSender.send(mimeMessage);
logger.error("Mailsentto: " + Arrays.asList(logTo) + "\nContent: " + content);
}
}.start();
} catch (Exception e) {
logger.error("emailServiceError error:" + e.getMessage(), e);
}
}
在上面的发邮件的代码中,使用了内部类如下:
new Thread() {
@Override
public void run() {
mailSender.send(mimeMessage);
logger.error("Mailsentto: " + Arrays.asList(logTo) + "\nContent: " + content);
}
}.start();
我觉得在这个地方做这个控制是很恰当的吧,为什么team leader让我删掉这个new Thread()的部分。
原话:“把new Thread全部删掉,这些邮件发送不了的bug都没有暴露出来; 邮件发送模块的代码采用异步发送方式,失去异常事务回滚的能力,new Thread要全部删除;” 不懂是什么意思啊?
问题:
1.为什么要去掉new Thread()?
2.在什么样的并发业务场景下,需要使用new Thread()这样的方式?有没有更好的解决方法?
3.在并发场景下,使用new Thread().start()的方式有什么弊端?每次new Thread新建对象性能会很差么?邮件服务也是当触发某个业务规则的时候,可能需要大量发送一下邮件,用线程池好不好呢?
伊谢尔伦2017-04-18 09:21:21
@有明 I have already talked about the troublesome aspects of anonymous internal classes. Let me explain it based on your business:
According to the existing code logic, what our email service should expose to the outside world is sendHtmlWithTemplate
这个方法,而不是 mailSender.send
,所以在我们对外暴露的sendHtmlWithTemplate
In this method, there is no need to restart a thread to send emails asynchronously, because for the caller, you actually need to tell it whether the email was sent successfully this time. , if it fails/exception occurs, what is the reason for the failure. If you follow your existing plan, it may feel to the outside world that no matter whether the email is sent successfully or fails, the outside world will not perceive it, which means that the email cannot be persisted and will be tried again after a while. So sending emails asynchronously should be left to your caller, not in your method
Assuming that our sending emails may be a time-consuming action, if we start a thread for every email that comes in, it means that many threads will be generated in the system. This means that there will be a lot of thread switching, thread switching, and thread switching will cause blocking and wake-up. These all involve the conversion of user mode and kernel mode or the switching of thread context, which is very CPU-intensive and extreme. In this case, if the system threads are not accumulated, the entire service will be DOWN and the service will be in an unavailable state. new Thread() is indeed a very expensive operation
If you send emails asynchronously correctly, you really need to do it in the thread pool
A better way is to send email messages through MQ (consider common problems with messages: 1. Will the message be lost? 2. What should I do if the message is resent), and leave it to a server that sends emails separately? Do it. Another way is to store it in the database table first. If the timeliness requirement is not very high, then start a timer and send it slowly.
高洛峰2017-04-18 09:21:21
Anonymous objects are very convenient, but anonymous objects are also devils. If used incorrectly, your application can collapse. Take your example as an example. If you do not control the parameters of sending emails, for example, if you continue to wait after the timeout occurs during sending, then this thread will become a lonely ghost. You cannot find it or close it. Drop it, is this what a programmer should do?
If you ask why your head asked you to remove this place, I can only say that he doesn’t trust your ability enough, so he doesn’t dare to let you control this devil.
If you ask what scenario is suitable, I can only say that there is no suitable scenario, only capable people.
黄舟2017-04-18 09:21:21
If you want to send a large number of emails, you can create a queue. If there are too many threads, it may not be good.
天蓬老师2017-04-18 09:21:21
Sorry, I just saw the problem now.
Please refer to @iMouseWu and @有明’s answers for details.
If you have ever written js, you can understand that the new Thread()
相当于ajax
request here is an asynchronous behavior. Before the thread task is completed, the method has returned to the caller (and will not throw an exception caused by sending an email) , this is what your leader said "These bugs that cannot send emails are not exposed" .
If you consider that the amount of concurrency is large, you can use redis
+kafka
(or other message components) to notify the mail service to send emails in the form of messages.