java mail 多线程发送邮件

转载地址:https://blog.csdn.net/ku360517703/article/details/50485710

背景

最近在做一个功能,需要批量或不定时散量发送邮件给不同的人。比方说注册功能,需要给注册人发送邮件,如果遇上系统新开放注册,有一定量的并发,如果一窝蜂地发,有可能造成smtp服务器拒绝421等状态

线程池

采用ThreadPoolExecutor线程池实现,他可以设定同时运行多少线程,多的任务可以排队。

 
  1. public ThreadPoolExecutor(int corePoolSize,

  2. int maximumPoolSize,

  3. long keepAliveTime,

  4. TimeUnit unit,

  5. BlockingQueue<Runnable> workQueue,

  6. RejectedExecutionHandler handler) {

    扫描二维码关注公众号,回复: 4482549 查看本文章
  7. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

  8. Executors.defaultThreadFactory(), handler);

  9. }

参数解释
corePoolSize:         核心线程数,会一直存活,即使没有任务,线程池也会维护线程的最少数量
maximumPoolSize: 线程池维护线程的最大数量
keepAliveTime:      线程池维护线程所允许的空闲时间,当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。
unit: 线程池维护线程所允许的空闲时间的单位、可选参数值为:TimeUnit中的几个静态属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。
workQueue: 线程池所使用的缓冲队列,常用的是:java.util.concurrent.ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue
handler: 线程池中的数量大于maximumPoolSize,对拒绝任务的处理策略,默认值ThreadPoolExecutor.AbortPolicy()。

 
  1. package mailTest;

  2.  
  3. import java.util.concurrent.BlockingQueue;

  4. import java.util.concurrent.ExecutorService;

  5. import java.util.concurrent.LinkedBlockingQueue;

  6. import java.util.concurrent.ThreadPoolExecutor;

  7. import java.util.concurrent.TimeUnit;

  8.  
  9. public class PoolSend {

  10. BlockingQueue<Runnable> workQueue;//任务队列

  11. ExecutorService es;//线程池的接口

  12.  
  13. public PoolSend() {

  14. workQueue = new LinkedBlockingQueue<>();//构造无界的任务队列,资源足够,理论可以支持无线个任务

  15. es = new ThreadPoolExecutor(2, 4, //2 core; 4 max

  16. 30,TimeUnit.SECONDS, workQueue, //30s keep alive

  17. new ThreadPoolExecutor.CallerRunsPolicy()); //任务失败重试

  18. }

  19.  
  20. public void send(Runnable task) {

  21. System.out.println("PoolSend start sending mail...");

  22. es.execute(task);//将任务放入线程池

  23. }

  24.  
  25. public void close() {// 关闭

  26. es.shutdown();

  27. }

  28.  
  29. }

任务

要将发送的功能封装成Runnable

 
  1. package mailTest;

  2.  
  3. import java.io.BufferedReader;

  4. import java.io.FileInputStream;

  5. import java.io.InputStreamReader;

  6. import java.util.Date;

  7. import java.util.Properties;

  8.  
  9. import javax.mail.BodyPart;

  10. import javax.mail.Message;

  11. import javax.mail.MessagingException;

  12. import javax.mail.Multipart;

  13. import javax.mail.Session;

  14. import javax.mail.Transport;

  15. import javax.mail.internet.MimeBodyPart;

  16. import javax.mail.internet.MimeMessage;

  17. import javax.mail.internet.MimeMultipart;

  18.  
  19. public class Sender implements Runnable {

  20. Properties props;

  21. Session session;

  22. MimeMessage msg;

  23.  
  24. public Sender() {

  25. System.out.println("constructor...");

  26. props = new Properties();

  27. props.put("mail.smtp.host", "smtp.163.com");

  28. session = Session.getInstance(props, null);

  29. msg = new MimeMessage(session);

  30. try {

  31. msg.setFrom("[email protected]");

  32. msg.setRecipients(Message.RecipientType.TO, "[email protected]");

  33. msg.setSubject("JavaMail hello world example");

  34. msg.setSentDate(new Date());

  35. String filename = "C:\\Users\\Tony\\Desktop\\a.html";

  36. BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF-8"));// 解决读取中文乱码

  37. String line = null;

  38. StringBuffer sb = new StringBuffer();

  39. while ((line = br.readLine()) != null) {

  40. sb.append(line);

  41. sb.append("\n");

  42. }

  43. br.close();

  44. BodyPart bodyPart = new MimeBodyPart();

  45. bodyPart.setContent(sb.toString(), "text/html;charset=UTF-8");

  46. Multipart multiPart = new MimeMultipart();

  47. multiPart.addBodyPart(bodyPart);

  48. msg.setContent(multiPart);

  49. msg.saveChanges();

  50. System.out.println("sent");

  51. // msg.setText("Hello, world!\n");

  52. } catch (Exception e) {

  53. e.printStackTrace();

  54. }

  55. }

  56.  
  57. public void send() {

  58. try {

  59. Transport.send(msg, "[email protected]", "password");

  60. System.out.println("sent success!");

  61. } catch (MessagingException mex) {

  62. System.out.println(new Date() + " send failed, exception: " + mex);

  63. }

  64. }

  65.  
  66. @Override

  67. public void run() {

  68. // TODO Auto-generated method stub

  69. send();

  70. }

  71.  
  72. }


 

专门一个任务类,实现Runnable接口,实现run函数,主要的内容跟发送的一样,就是多了接口的函数

然而这只是一个例子,性能不行

因为每个线程都读本地的一个文本来构造发送函数,简直不科学,具体怎么封装,还得看大家发挥啦

测试了同时来100个发送请求,应该能够支持系统的需求了,大约每秒发1~5封,大概也是163设置的限制了,没有失败哟

费时的io调用,使用了多线程,线程池,性能大大提高,缓冲了蜂拥的请求,因为对邮件发送,可以忍受几秒的延迟,但是如果页面卡住几秒就不好了

失败还有重发的功能,简直不能再棒了

猜你喜欢

转载自blog.csdn.net/u013208718/article/details/81276612