찾다

 >  Q&A  >  본문

java - new Thread().start内部类的使用场景?

下面的这个方法是发邮件的抽象出来的一个公用方法:

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新建对象性能会很差么?邮件服务也是当触发某个业务规则的时候,可能需要大量发送一下邮件,用线程池好不好呢?

阿神阿神2802일 전1559

모든 응답(4)나는 대답할 것이다

  • 伊谢尔伦

    伊谢尔伦2017-04-18 09:21:21

    @Youming님은 이미 익명 내부 클래스의 불편한 점을 언급하셨습니다. 귀하의 비즈니스를 기준으로 설명하겠습니다.

    1. 기존 코드 로직에 따르면 우리 이메일 서비스가 외부에 노출해야 하는 sendHtmlWithTemplate 메소드는 mailSender.send가 아닌 sendHtmlWithTemplate 메소드여야 하므로 다시 노출할 필요가 없습니다. 우리가 외부에 공개하는

      메소드. 이메일을 비동기적으로 보내는 스레드를 시작하세요. 왜냐하면 호출자에게는 이번에 이메일 전송이 성공했는지, 실패/예외가 발생했는지 알려줘야 하기 때문입니다. 실패의 이유였습니다. 기존 계획을 따르면 이메일이 성공적으로 전송되거나 실패하더라도 외부 세계가 이를 인식하지 못한다고 외부 세계에 느껴질 수 있습니다. 이는 이메일이 지속되지 않고 잠시 후 다시 시도된다는 의미입니다. . 따라서 비동기식으로 이메일을 보내는 것은 귀하의 방법이 아닌 호출자에게 맡겨야 합니다
    2. 이메일을 보내는 데 시간이 많이 걸리는 작업이라고 가정하면, 들어오는 모든 이메일에 대해 스레드를 시작하면 시스템에 많은 스레드가 있다는 의미입니다. 즉, 스레드 전환이 많이 발생하고 스레드 전환으로 인해 차단 및 깨우기가 발생합니다. 이 모든 작업에는 사용자 모드와 커널 모드의 전환 또는 스레드 컨텍스트 전환이 포함되며 이는 매우 CPU 집약적이고 극단적입니다. 이 경우 시스템 스레드가 누적되지 않으면 서비스 전체가 DOWN이 되어 서비스를 사용할 수 없는 상태가 된다. new Thread()는 실제로 매우 비용이 많이 드는 작업입니다
    3. 이메일을 비동기식으로 올바르게 보내려면 스레드 풀에서 해야 합니다
    4. 더 좋은 방법은 MQ를 통해 이메일 메시지를 보내는 것입니다(메시지의 일반적인 고통스러운 문제를 고려하십시오: 1. 메시지가 손실됩니까? 2. 메시지가 재전송되면 어떻게 해야 합니까?). 별도의 서버 메일을 보내는 서버가 이를 수행합니다. 또 다른 방법은 적시성 요구 사항이 그다지 높지 않은 경우 먼저 데이터베이스 테이블에 저장하는 것입니다. 그런 다음 타이머를 시작하고 천천히 보냅니다.
    <🎜>

    회신하다
    0
  • 高洛峰

    高洛峰2017-04-18 09:21:21

    익명 개체는 매우 편리하지만 제대로 사용하지 않으면 애플리케이션이 붕괴됩니다. 예를 들어 이메일 전송 매개변수를 제어하지 않는 경우, 예를 들어 전송 중에 시간 초과가 발생한 후에도 계속 기다리면 이 스레드를 찾을 수 없거나 닫을 수 없습니다. 그만둬라, 이것이 프로그래머가 해야 할 일인가?
    당신 머리가 왜 이곳을 없애라고 했는지 묻는다면, 그 사람은 당신의 능력을 충분히 신뢰하지 않아서 감히 당신이 이 악마를 통제하도록 놔두지 않을 것이라고밖에 말할 수 없습니다.
    어떤 시나리오에 적합하냐고 물으신다면 적합한 시나리오는 없고 능력 있는 사람만 가능하다고 말씀드릴 수 있습니다.

    회신하다
    0
  • 黄舟

    黄舟2017-04-18 09:21:21

    많은 양의 이메일을 보내고 싶다면 대기열을 만들 수 있습니다. 스레드가 너무 많으면 좋지 않을 수 있습니다.

    회신하다
    0
  • 天蓬老师

    天蓬老师2017-04-18 09:21:21

    죄송합니다. 이제 문제를 확인했습니다.

    자세한 내용은 @iMouseWu 및 @유명 님의 답변을 참고하세요.

    js를 작성한 적이 있다면 여기서 new Thread()가 비동기 동작인 ajax 요청과 동일하다는 것을 이해할 수 있습니다. 이는 스레드 작업이 완료되기 전에 메서드가 호출자에게 반환됩니다. no 이메일을 보내면 예외가 발생합니다) 리더님이 "이 이메일을 보낼 수 없는 버그는 노출되지 않았습니다"라고 말씀하셨습니다.

    동시성이 크다고 생각되면 redis+kafka(또는 기타 메시지 구성 요소)를 사용하여 이메일 서비스에 메시지 형식으로 이메일을 보내도록 알릴 수 있습니다.

    회신하다
    0
  • 취소회신하다