下面的这个方法是发邮件的抽象出来的一个公用方法:
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
@Youming は、匿名内部クラスの問題点についてすでに言及しました。あなたのビジネスに基づいて説明させてください:
既存のコード ロジックによれば、電子メール サービスは sendHtmlWithTemplate
ではなく mailSender.send
メソッドを外部に公開する必要があるため、公開する sendHtmlWithTemplate
メソッドを再公開する必要はありません。外部の世界では、電子メールを非同期に送信するためのスレッドを開始します。これは、呼び出し側に対して、実際に電子メールが今回正常に送信されたかどうか、失敗または例外が発生した場合は失敗の理由を通知する必要があるためです。既存の計画に従うと、電子メールの送信が成功したか失敗したかに関係なく、外部の世界にはそれが認識されないように感じるかもしれません。つまり、電子メールは永続化できず、しばらくしてから再試行されることになります。 。したがって、メールの非同期送信はメソッド
電子メールの送信が時間のかかるアクションであると仮定すると、受信するすべての電子メールに対してスレッドを開始すると、システム内に多数のスレッドが存在することになります。これは、大量のスレッド切り替えが発生し、スレッド切り替えによってブロッキングとウェイクアップが発生することを意味します。これらにはすべて、ユーザー モードとカーネル モードの変換、またはスレッド コンテキストの切り替えが含まれ、非常に CPU を使用します。この場合、システム スレッドが蓄積されないと、サービス全体がダウンし、サービスが利用できない状態になります。 new Thread() は確かに非常に高価な操作です
メールを非同期で正しく送信したい場合は、スレッド プールで行う必要があります
より良い方法は、MQ を介して電子メール メッセージを送信し (メッセージに関する一般的な厄介な問題を考慮してください: 1. メッセージは失われますか? 2. メッセージが再送信された場合はどうするか)、そのままにしておきます。別のサーバー メールを送信するサーバーがそれを行います。もう 1 つの方法は、適時性の要件がそれほど高くない場合は、最初にデータベース テーブルに保存し、タイマーを開始してゆっくり送信することです。
高洛峰2017-04-18 09:21:21
匿名オブジェクトは非常に便利ですが、適切に使用しないとアプリケーションが崩壊してしまう悪魔でもあります。例として、電子メールの送信パラメータを制御しない場合、たとえば、送信中にタイムアウトが発生した後も待機し続けると、このスレッドは孤独な幽霊になってしまい、見つけることも閉じることもできません。やめてください、これがプログラマーのやるべきことですか?
なぜあなたの頭があなたにこの場所を取り除くように頼んだのかと尋ねると、彼はあなたの能力を十分に信頼していないので、あなたにこの悪魔を制御させる勇気がないとしか言いません。
どのようなシナリオに適しているか尋ねられますが、適切なシナリオなど存在せず、有能な人材だけであるとしか言えません。
天蓬老师2017-04-18 09:21:21
申し訳ありませんが、今問題を確認しました。
詳しくは@iMouseWuと@有明の回答を参照してください。
js を書いたことがある人なら、ここでの new Thread()
が ajax
リクエストと同等であり、スレッド タスクが完了する前にメソッドが呼び出し元に戻っていることを理解できると思います。いいえ、電子メールの送信によって引き起こされる例外がスローされます)、これはリーダーが言ったことです 「これらの電子メールを送信できないバグは公開されていません」 。
同時実行の量が多いと考えられる場合は、redis
+kafka
(または他のメッセージ コンポーネント) を使用して、 電子メール サービスにメッセージの形式で電子メールを送信するように 通知できます。