工作中,或多或少都会用到多线程处理问题。今日就遇到一个问题来作为经验留存,内容稍作简单,见解较浅,欢迎留言补充
问题:用户发单之后,发送多条邮件通知
用户在请求一个发单接口之后,需要发送多条邮件通知给目标人。
发单成功返回给客户端一条成功通知:{"code":0,"message":"ok"}
理想状态下是:请求发单成功 ——> 客户端即刻收到成功通知(不必等待邮件发送)
一般邮件发送需要占用一定的时间,导致不能及时吧成功的消息发回给客户端,影响体验。所以需要在发送邮件的方法中,加入异步处理流程。
实现
框架:SpringMVC
一开始,我在发送邮件方法上,加上注解@Async,发现在controller中调用,没有效果
public class SendEmailHelper { private static Logger logger = Logger.getLogger(SendEmailHelper.class); @Async public static void send(String title, List<String> toList, String content) { SendEmailHead head = new SendEmailHead("firefly", "212faef1"); SendEmailBody body = new SendEmailBody(); body.setModel(new SendEmailModel(title, content)); body.setTemplateName("legalNewOrder"); body.setTitle(title); body.setToList(toList); try { XStream xStreamJ = new XStream(new JsonHierarchicalStreamDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE); } }); String json = xStreamJ.toXML(new SendEmailData(head, body)); logger.info("请求邮件发送数据:" + json); Thread.sleep(10000); // 模拟时间 logger.info("发送邮件完成"); } catch (Exception e) { logger.error("法务发单邮件发送失败:" + e.getMessage()); } } }
后来查询一些文档, 目前找到两种解决方案,问题解决
注意:以下代码建议使用第一种方案,spring自动维护线程池,第二种方案是每次都会新建一个线程,若想要使用第二种,最好创建一个线程管理来维护线程池来配合使用。
第一种:新建一个线程运行
public class SendEmailHelper { private static Logger logger = Logger.getLogger(SendEmailHelper.class); public static void send(String title, List<String> toList, String content) { // 新建线程 new Thread() { public void run() { SendEmailHead head = new SendEmailHead("firefly", "212faef1"); SendEmailBody body = new SendEmailBody(); body.setModel(new SendEmailModel(title, content)); body.setTemplateName("legalNewOrder"); body.setTitle(title); body.setToList(toList); try { XStream xStreamJ = new XStream(new JsonHierarchicalStreamDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE); } }); String json = xStreamJ.toXML(new SendEmailData(head, body)); logger.info("请求邮件发送数据:" + json); Thread.sleep(10000); // 模拟请求时间 logger.info("发送邮件完成"); } catch (Exception e) { logger.error("法务发单邮件发送失败:" + e.getMessage()); } } }.start(); } }
第二种方法:使用注解 @Async
把SendEmailHelper,改造成Service,然后使用注解@Async
XML配置
<bean id="sendEmailService" class="com.wusong.firefly.push.message.email.service.impl.SendEmailServiceImpl"> </bean>
java配置
public interface SendEmailService { void send(String title, List<String> toList, String content); } // 实现类 public class SendEmailServiceImpl implements SendEmailService{ private static Logger logger = Logger.getLogger(SendEmailServiceImpl.class); @Override @Async public void send(String title, List<String> toList, String content) { SendEmailHead head = new SendEmailHead("firefly", "212faef1"); SendEmailBody body = new SendEmailBody(); body.setModel(new SendEmailModel(title, content)); body.setTemplateName("legalNewOrder"); body.setTitle(title); body.setToList(toList); try { XStream xStreamJ = new XStream(new JsonHierarchicalStreamDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE); } }); String json = xStreamJ.toXML(new SendEmailData(head, body)); logger.info("请求邮件发送数据:" + json); Thread.sleep(10000); // 模拟请求时间 logger.info("发送邮件完成"); } catch (Exception e) { logger.error("法务发单邮件发送失败:" + e.getMessage()); } } }