资讯专栏INFORMATION COLUMN

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

jsummer / 1014人阅读

摘要:邮件信息发件人信息每个线程发送邮件的最大数量去除重复的收件人存储发送失败的收件人存储发送成功的收件人记录发送邮件的次数每个收件人创建一个线程用来发送邮件处理结果

前言

之前用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;
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67656.html

相关文章

  • Flask Web Development —— Email

    摘要:函数携带目的地址主题邮件体模板和一组关键字参数。许多扩展操作是在假设有活动的应用程序和请求上下文的情况下进行的。但是当函数在一个不同的线程上执行,应用程序上下文需要人为地创建使用。例如,执行函数可以将邮件发送到的任务队列中。 许多类型的应用程序都会在某些事件发生的时候通知用户,常用的沟通方法就是电子邮件。尽管在Flask应用程序中,可以使用Python标准库中的smtplib包来发送电...

    SKYZACK 评论0 收藏0
  • JavaMail邮件发送不成功的那些坑人情况及分析说明

    摘要:网上也有不少人反馈用手机客户端无法使用新浪邮箱发送邮件,随后我尝试用登录新浪邮箱,也出现只能接收邮件而不能发送邮件的情况。三附录错误码及建议解决方法发送邮件成功却收不到邮件或收到邮件无主题无收件人乱码新浪邮箱诚信平台 前言   JavaMail的使用本身并不难,网上有不少案例,简单易懂,而且有详细的中文注解。但是由于JavaMail的机制设置不够完善,特别是异常出错时的参考信息太少,给...

    y1chuan 评论0 收藏0
  • 结合Spring发送邮件的四种正确姿势,你知道几种?

    摘要:我拿网易邮箱账号举例子,那么我们如何才能让你的邮箱账号可以利用第三方发送邮件这里的第三方就是我们即将编写的程序。 一 前言 测试所使用的环境 测试使用的环境是企业主流的SSM 框架即 SpringMVC+Spring+Mybatis。为了节省时间,我直接使用的是我上次的SSM项目中整合Echarts开发该项目已经搭建完成的SSM环境。 标题说的四种姿势指的是哪四种姿势? 发送text...

    doodlewind 评论0 收藏0

发表评论

0条评论

jsummer

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<