【javaMail】【3.多线程发邮件】java mail 多线程发送邮件

背景

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


线程池

采用ThreadPoolExecutor线程池实现,他可以设定同时运行多少线程,多的任务可以排队。
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

参数解释
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()。

package mailTest;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class PoolSend {
	BlockingQueue workQueue;//任务队列
	ExecutorService es;//线程池的接口

	public PoolSend() {
		workQueue = new LinkedBlockingQueue<>();//构造无界的任务队列,资源足够,理论可以支持无线个任务
		es = new ThreadPoolExecutor(2, 4, //2 core; 4 max
				30,TimeUnit.SECONDS, workQueue, //30s keep alive
				new ThreadPoolExecutor.CallerRunsPolicy()); //任务失败重试
	}

	public void send(Runnable task) {
		System.out.println("PoolSend start sending mail...");
		es.execute(task);//将任务放入线程池
	}

	public void close() {// 关闭
		es.shutdown();
	}

}


任务

要将发送的功能封装成Runnable

package mailTest;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class Sender implements Runnable {
	Properties props;
	Session session;
	MimeMessage msg;

	public Sender() {
		System.out.println("constructor...");
		props = new Properties();
		props.put("mail.smtp.host", "smtp.163.com");
		session = Session.getInstance(props, null);
		msg = new MimeMessage(session);
		try {
			msg.setFrom("[email protected]");
			msg.setRecipients(Message.RecipientType.TO, "[email protected]");
			msg.setSubject("JavaMail hello world example");
			msg.setSentDate(new Date());
			String filename = "C:\\Users\\Tony\\Desktop\\a.html";
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF-8"));// 解决读取中文乱码
			String line = null;
			StringBuffer sb = new StringBuffer();
			while ((line = br.readLine()) != null) {
				sb.append(line);
				sb.append("\n");
			}
			br.close();
			BodyPart bodyPart = new MimeBodyPart();
			bodyPart.setContent(sb.toString(), "text/html;charset=UTF-8");
			Multipart multiPart = new MimeMultipart();
			multiPart.addBodyPart(bodyPart);
			msg.setContent(multiPart);
			msg.saveChanges();
			System.out.println("sent");
			// msg.setText("Hello, world!\n");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void send() {
		try {
			Transport.send(msg, "[email protected]", "password");
			System.out.println("sent success!");
		} catch (MessagingException mex) {
			System.out.println(new Date() + " send failed, exception: " + mex);
		}
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		send();
	}

}


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

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

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

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

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

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



ps:最近在准备学校最后一门考试,都还没整合到系统中呢...所以代码还是乱乱的

你可能感兴趣的:(Java)