以前用java mail发送邮件,都是分给每一个邮件一个线程,在邮件发送成功后,由该子线程将mail的信息(发送成功的邮箱和未发送的邮箱)存储到数据库中。java
如今须要处理一封邮件有上万收件人的状况,若是还按照以前每一个mail一个线程,发送的效率过低了,所以须要将一封邮件分到多个线程中去执行,让每一个子线程处理一部分收件人,可是子线程执行完成后更新mail的信息,会出现数据覆盖的状况。数据库
若是每一个子线程执行完后能将发送邮件的信息返回给主线程,那么咱们就能够在全部子线程结束后再存储mail的信息了。ide
Runnable任务不返回任何值,若是你但愿在任务完成时可以返回一个值,那么能够实现Callable接口而不是Runnable接口,Callable是一种具备类型参数的泛型,它的类型参数表示的是从方法call()中返回的值,而且必须使用ExecutorService.submit()方法调用它。函数
public class TaskWithResult implements Callable<String>{ @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<String> 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()方法会阻塞主线程。this
在获取返回结果时,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<String> sendTos = Arrays.stream(mail.getSendTo().split(";")).distinct().collect(Collectors.toList()); // 存储发送失败的收件人 String sendTo = ""; // 存储发送成功的收件人 String sended = ""; // 记录发送邮件的次数 int sendTimes = 0; Mailer.setSender(sender); List<Future<List<String>>> futures = new ArrayList<>(); // 每100个收件人建立一个线程用来发送邮件 for (int i = 0; i <= sendTos.size()/mail_limit; i++ ){ List<String> 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<List<String>> result = exec.submit(mailer); futures.add(result); } // 处理结果 for (Future<List<String>> 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; } }