【Netty】Future & Promise

Future & Promise

在异步处理时,经常用到这两个接口

首先要说明 netty 中的 Future 与 jdk 中的 Future 同名,但是是两个接口,netty 的 Future 继承自 jdk 的 Future,而 Promise 又对 netty Future 进行了扩展

  • jdk Future 只能同步等待任务结束(或成功、或失败)才能得到结果

  • netty Future 可以同步等待任务结束得到结果,也可以异步方式得到结果,但都是要等任务结束

  • netty Promise 不仅有 netty Future 的功能,而且脱离了任务独立存在,只作为两个线程间传递结果的容器

功能/名称jdk Futurenetty FuturePromise
cancel取消任务--
isCanceled任务是否取消--
isDone任务是否完成,不能区分成功失败--
get获取任务结果,阻塞等待--
getNow-获取任务结果,非阻塞,还未产生结果时返回 null-
await-等待任务结束,如果任务失败,不会抛异常,而是通过 isSuccess 判断-
sync-等待任务结束,如果任务失败,抛出异常-
isSuccess-判断任务是否成功-
cause-获取失败信息,非阻塞,如果没有失败,返回null-
addLinstener-添加回调,异步接收结果-
setSuccess--设置成功结果
setFailure--设置失败结果

下面是各个方式的演示用例

例1

同步处理任务成功

DefaultEventLoop eventExecutors = new DefaultEventLoop();
DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);
​
eventExecutors.execute(()->{
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.debug("set success, {}",10);
    promise.setSuccess(10);
});
​
log.debug("start...");
log.debug("{}",promise.getNow()); // 还没有结果
log.debug("{}",promise.get());

输出

例2

异步处理任务成功

DefaultEventLoop eventExecutors = new DefaultEventLoop();
DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);
​
// 设置回调,异步接收结果
promise.addListener(future -> {
    // 这里的 future 就是上面的 promise
    log.debug("{}",future.getNow());
});
​
// 等待 1000 后设置成功结果
eventExecutors.execute(()->{
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.debug("set success, {}",10);
    promise.setSuccess(10);
});
​
log.debug("start...");

例3

同步处理任务失败 - sync & get

DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);
​
        eventExecutors.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            RuntimeException e = new RuntimeException("error...");
            log.debug("set failure, {}", e.toString());
            promise.setFailure(e);
        });
​
        log.debug("start...");
        log.debug("{}", promise.getNow());
        promise.get(); // sync() 也会出现异常,只是 get 会再用 ExecutionException 包一层异常

输出

例4

同步处理任务失败 - await

DefaultEventLoop eventExecutors = new DefaultEventLoop();
DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

eventExecutors.execute(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    RuntimeException e = new RuntimeException("error...");
    log.debug("set failure, {}", e.toString());
    promise.setFailure(e);
});

log.debug("start...");
log.debug("{}", promise.getNow());
promise.await(); // 与 sync 和 get 区别在于,不会抛异常
log.debug("result {}", (promise.isSuccess() ? promise.getNow() : promise.cause()).toString());

例5

异步处理任务失败

DefaultEventLoop eventExecutors = new DefaultEventLoop();
DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);
​
promise.addListener(future -> {
    log.debug("result {}", (promise.isSuccess() ? promise.getNow() : promise.cause()).toString());
});
​
eventExecutors.execute(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    RuntimeException e = new RuntimeException("error...");
    log.debug("set failure, {}", e.toString());
    promise.setFailure(e);
});
​
log.debug("start...");

输出

例6

await 死锁检查

DefaultEventLoop eventExecutors = new DefaultEventLoop();
DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);
​
eventExecutors.submit(()->{
    System.out.println("1");
    try {
        promise.await();
        // 注意不能仅捕获 InterruptedException 异常
        // 否则 死锁检查抛出的 BlockingOperationException 会继续向上传播
        // 而提交的任务会被包装为 PromiseTask,它的 run 方法中会 catch 所有异常然后设置为 Promise 的失败结果而不会抛出
    } catch (Exception e) { 
        e.printStackTrace();
    }
    System.out.println("2");
});
eventExecutors.submit(()->{
    System.out.println("3");
    try {
        promise.await();
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("4");
});

输出

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
Netty是一个网络编程框架,它主要用于构建高性能、高可靠性的网络应用程序。然而,Netty本身并不提供发送邮件的功能,它更适用于实现基于TCP或UDP的网络通信。 如果你想在Java中使用Netty发送邮件,你可以借助JavaMail API来实现。JavaMail API是Java平台的标准API,它提供了发送和接收电子邮件的功能。 以下是一个使用NettyJavaMail API发送简单邮件的示例代码: ```java import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; import io.netty.util.concurrent.Promise; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.mail.internet.MimeBodyPart; import javax.activation.DataHandler; import javax.activation.FileDataSource; import java.util.Properties; public class EmailSender { public static void main(String[] args) { // 配置SMTP服务器和认证信息 Properties props = new Properties(); props.put("mail.smtp.host", "smtp.example.com"); props.put("mail.smtp.port", "587"); props.put("mail.smtp.auth", "true"); // 创建会话 Session session = Session.getInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("your_username", "your_password"); } }); // 创建邮件消息 MimeMessage message = new MimeMessage(session); try { // 设置发件人 message.setFrom(new InternetAddress("sender@example.com")); // 设置收件人 message.addRecipient(Message.RecipientType.TO, new InternetAddress("recipient@example.com")); // 设置主题 message.setSubject("Test Email"); // 创建正文部分 MimeBodyPart textPart = new MimeBodyPart(); textPart.setText("This is the email content."); // 创建附件部分 MimeBodyPart attachmentPart = new MimeBodyPart(); FileDataSource fileDataSource = new FileDataSource("path_to_attachment_file"); attachmentPart.setDataHandler(new DataHandler(fileDataSource)); attachmentPart.setFileName(fileDataSource.getName()); // 创建多部分消息 MimeMultipart multipart = new MimeMultipart(); multipart.addBodyPart(textPart); multipart.addBodyPart(attachmentPart); // 设置消息内容 message.setContent(multipart); // 使用Netty发送邮件 Promise<Void> promise = new DefaultPromise<>(session.channel().eventLoop()); Transport transport = session.getTransport("smtp"); transport.connect(); transport.sendMessage(message, message.getAllRecipients(), new SendListener(promise)); transport.close(); // 等待邮件发送完成 Future<Void> future = promise; future.addListener(new FutureListener<Void>() { @Override public void operationComplete(Future<Void> future) throws Exception { if (future.isSuccess()) { System.out.println("Email sent successfully."); } else { System.out.println("Failed to send email: " + future.cause().getMessage()); } } }); } catch (Exception ex) { ex.printStackTrace(); } } private static class SendListener extends SendMailTransportListener { private final Promise<Void> promise; public SendListener(Promise<Void> promise) { this.promise = promise; } @Override public void messageDelivered(TransportEvent e) { promise.setSuccess(null); } @Override public void messageNotDelivered(TransportEvent e) { promise.setFailure(e.getException()); } @Override public void messagePartiallyDelivered(TransportEvent e) { promise.setFailure(e.getException()); } } } ``` 请注意,上述代码中的SMTP服务器和认证信息需要根据你的实际情况进行配置。另外,需要将"sender@example.com"和"recipient@example.com"替换为实际的发件人和收件人邮箱地址。最后,将"path_to_attachment_file"替换为要附加的文件的路径。 这只是一个简单的示例,你可以根据自己的需求进行扩展和定制。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五敷有你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值