java 多人发送邮件_java mail 多线程处理大量收件人,并将发送结果储存到数据库...

前言

之前用java mail发送邮件,都是分给每个邮件一个线程,在邮件发送成功后,由该子线程将mail的信息(发送成功的邮箱和未发送的邮箱)存储到数据库中。

现在需要处理一封邮件有上万收件人的情况,如果还按照之前每个mail一个线程,发送的效率太低了,因此需要将一封邮件分到多个线程中去执行,让每个子线程处理一部分收件人,但是子线程执行完成后更新mail的信息,会出现数据覆盖的情况。

如果每个子线程执行完后能将发送邮件的信息返回给主线程,那么我们就可以在所有子线程结束后再存储mail的信息了。

Java Callable

Runnable任务不返回任何值,如果你希望在任务完成时能够返回一个值,那么可以实现Callable接口而不是Runnable接口,Callable是一种具有类型参数的泛型,它的类型参数表示的是从方法call()中返回的值,并且必须使用ExecutorService.submit()方法调用它。

public class TaskWithResult implements Callable{

@Override

public String call() throws Exception {

return "result";

}

}

public class TaskDemo{

public static void main(String[] args) {

ExecutorService exec = Executors.newCachedThreadPool();

TaskWithResult task = new TaskWithResult();

Future future = exec.submit(task);

try {

System.out.println(future.get());

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

}

/* Output:

result

*/

submit()方法会产生Future对象,你可以用isDone()来查询Future是否已经完成,任务完成时,可以用get()方法获取任务的返回值,如果任务没有完成,调用get()方法会阻塞主线程。

代码实现

在获取返回结果时,get()会阻塞主线程,为了使发送邮件的函数不被阻塞,我们需要新创建一个线程来运行发送邮件的子线程。

类Mailer为实现了Callable的发送邮件的具体实现的代码。Mail为邮件的实体。

public class MailerTask extends Thread {

private Mail mail;//邮件信息

private String sender;//发件人信息

//每个线程发送邮件的最大数量

private static final int mail_limit = 100;

public static void send(Mail mail, String sender){

MailerTask mailerTask = new MailerTask();

mailerTask.setMail(mail);

mailerTask.setSender(sender);

mailerTask.start();

}

@Override

public void run() {

ExecutorService exec = Executors.newFixedThreadPool(20);

// 去除重复的收件人

List sendTos = Arrays.stream(mail.getSendTo().split(";")).distinct().collect(Collectors.toList());

// 存储发送失败的收件人

String sendTo = "";

// 存储发送成功的收件人

String sended = "";

// 记录发送邮件的次数

int sendTimes = 0;

Mailer.setSender(sender);

List>> futures = new ArrayList<>();

// 每100个收件人创建一个线程用来发送邮件

for (int i = 0; i <= sendTos.size()/mail_limit; i++ ){

List subSendTos = sendTos.stream().skip(i*mail_limit).limit(mail_limit).collect(Collectors.toList());

String subSendTo = subSendTos.stream().collect(Collectors.joining(";"));

mail.setSendTo(subSendTo);

Mailer mailer = new Mailer();

mailer.setMail(mail);

Future> result = exec.submit(mailer);

futures.add(result);

}

// 处理结果

for (Future> future : futures){

try {

String subSendTo = future.get().get(0);

String subSended = future.get().get(1);

String subtimes = future.get().get(2);

if (subSendTo != "") {

sendTo = sendTo + subSendTo + ";";

}

if (subSended != "" && subSended != null) {

sended += subSended;

sended += ";";

}

sendTimes += Integer.valueOf(subtimes);

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

exec.shutdown();

mail.setSendTo(sendTo);

mail.setSended(sended);

mail.setSendTimes(sendTimes);

mail.setFinishDate(sendTo.isEmpty() ? new Date() : null);

MailService mailService = (MailService) ServiceFactory.getSpringBean("mailService");

mailService.saveMail(mail);

}

public void setSender(String sender) {

this.sender = sender;

}

public void setMail(Mail mail) {

this.mail = mail;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值