【异步】Java 的 8 种异步实现方式

这篇具有很好参考价值的文章主要介绍了【异步】Java 的 8 种异步实现方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

异步执行对于开发者来说并不陌生,在实际的开发过程中,很多场景多会使用到异步,相比同步执行,异步可以大大缩短请求链路耗时时间,比如:发送短信、邮件。

异步的八种实现方式:

  1. 线程异步 Thread/Runnable
  2. Future + Callable
  3. 异步框架 CompletableFuture
  4. Spring 注解 @Async
  5. Spring ApplicationEvent 事件
  6. 第三方异步框架,比如 Hutool 的 ThreadUtil
  7. Guava 异步
  8. 消息队列

1、线程异步

public class ThreadTest implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        new Thread(threadTest).start();
    }

}

当然,如果每次都创建一个 Thread 线程,频繁的创建、销毁,浪费系统资源,我们可以采用线程池:【Thread】线程池的 7 种创建方式及自定义线程池

2、Future 异步

public class FutureTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        Future<String> future = executor.submit(() -> {
            Thread.sleep(2000);
            return "this is future execute final result!!!";
        });
        //这里需要返回值时会阻塞主线程
        String result = future.get();
        System.out.println(result);
        executor.shutdown();
    }

}

Future的不足之处的包括以下几点:

  1. 无法被动接收异步任务的计算结果:虽然我们可以主动将异步任务提交给线程池中的线程来执行,但是待异步任务执行结束之后,主线程无法得到任务完成与否的通知,它需要通过get方法主动获取任务执行的结果。
  2. Future件彼此孤立:有时某一个耗时很长的异步任务执行结束之后,你想利用它返回的结果再做进一步的运算,该运算也会是一个异步任务,两者之间的关系需要程序开发人员手动进行绑定赋予,Future并不能将其形成一个任务流(pipeline),每一个Future都是彼此之间都是孤立的,所以才有了后面的CompletableFuture,CompletableFuture就可以将多个Future串联起来形成任务流。
  3. Futrue没有很好的错误处理机制:截止目前,如果某个异步任务在执行发的过程中发生了异常,调用者无法被动感知,必须通过捕获get方法的异常才知晓异步任务执行是否出现了错误,从而在做进一步的判断处理

3、CompletableFuture
关于 CompletableFuture 更多详情请看:【异步】Futurn、FutureTask、CompletionService、CompletableFuture

public static void thenRunAsync() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread() + " cf1 do something....");
        return 1;
    });
    CompletableFuture<Void> cf2 = cf1.thenRunAsync(() -> {
        System.out.println(Thread.currentThread() + " cf2 do something...");
    });
    //等待任务1执行完成
    System.out.println("cf1结果->" + cf1.get());
    //等待任务2执行完成
    System.out.println("cf2结果->" + cf2.get());
}

4、Spring 注解 @Async

@Configuration
public class ThreadPoolConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        //返回可用处理器的Java虚拟机的数量 12
        int i = Runtime.getRuntime().availableProcessors();
        System.out.println("系统最大线程数  : " + i);
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程池大小
        executor.setCorePoolSize(16);
        //最大线程数
        executor.setMaxPoolSize(20);
        //配置队列容量,默认值为Integer.MAX_VALUE
        executor.setQueueCapacity(99999);
        //活跃时间
        executor.setKeepAliveSeconds(60);
        //线程名字前缀
        executor.setThreadNamePrefix("asyncServiceExecutor -");
        //设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行
        executor.setAwaitTerminationSeconds(60);
        //等待所有的任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }

}
@Service
@EnableAsync
public class AsyncServiceImpl implements AsyncService {

    @Override
    @Async("taskExecutor")
    public String sendSms() {
        System.out.println(Thread.currentThread().getName());
        return null;
    }

    @Override
    @Async("taskExecutor")
    public String sendEmail() {
        System.out.println(Thread.currentThread().getName());
        return null;
    }

}

在实际项目中, 使用 @Async 调用线程池,推荐等方式是是使用自定义线程池的模式,不推荐直接使用 @Async 直接实现异步

5、Spring ApplicationEvent 事件

Spring 中使用事件只需要以下的几个步骤:

  1. 定义事件,继承 ApplicationEvent
  2. 定义监听,要么实现 ApplicationListener 接口,要么在方法上添加 @EventListener 注解
  3. 定义发布事件接口,调用 ApplicationContext.publishEvent() 或者 ApplicationEventPublisher.publishEvent();
  4. 业务调用发布事件
@Getter
@Setter
public class BaseEvent<T> extends ApplicationEvent {

    private T data;

    public BaseEvent(Object source) {
        super(source);
    }

    public BaseEvent(Object source, T data) {
        super(source);
        this.data = data;
    }

}
@Component
public class BaseEventListener implements ApplicationListener<BaseEvent<UserVo>> {

    @Override
    @Async("taskExecutor")
    public void onApplicationEvent(BaseEvent<UserVo> baseEvent) {
        UserVo eventData = baseEvent.getData();
        // TODO 业务处理
    }

}
@Autowired
private ApplicationContext applicationContext;

@GetMapping("/pubEvent")
public void pubEvent() {
    BaseEvent<UserVo> baseEvent = new BaseEvent<>("event", new UserVo());
    applicationContext.publishEvent(baseEvent);
}

6、Hutool 的 ThreadUtil

public static void main(String[] args) {
    for (int i = 0; i < 3; i++) {
        ThreadUtil.execAsync(() -> {
            ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
            int number = threadLocalRandom.nextInt(20) + 1;
            System.out.println(number);
        });
        log.info("当前第:" + i + "个线程");
    }

    log.info("task finish!");
}

7、 Guava 异步

public static void test() {
    ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
    final ListenableFuture<Integer> listenableFuture = executorService.submit(() -> {
        log.info("callable execute...");
        TimeUnit.SECONDS.sleep(1);
        return 1;
    });

    Futures.addCallback(listenableFuture, new FutureCallback<Integer>() {
        @Override
        public void onSuccess(@Nullable Integer integer) {
            System.out.println("Get listenable future's result with callback " + integer);
        }
        @Override
        public void onFailure(Throwable throwable) {
            throwable.printStackTrace();
        }
    }, Executors.newCachedThreadPool());
}

8、 消息队列

常用的消息队列:RabbitMqRocketMq文章来源地址https://www.toymoban.com/news/detail-692576.html

到了这里,关于【异步】Java 的 8 种异步实现方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 的异步编程 (5 种异步实现方式详解)

    1.创建一个异步线程 2.创建主线程,在主线程中创建异步线程执行异步线程,实现异步编程 3.优化:由于线程的频繁创建和销毁浪费系统资源,我们可以使用线程池进行优化 线程池的使用:创建一个类,将线程池设置为全局变量 执行线程时只需要创建执行对象调用执行方法就

    2024年02月14日
    浏览(43)
  • Java实现异步的8种方式

    一、前言         异步执行对于开发者来说并不陌生,在实际的开发过程中,很多场景多会使用到异步,相比同步执行,异步可以大大缩短请求链路耗时时间,比如:「发送短信、邮件、异步更新等」,这些都是典型的可以通过异步实现的场景。     二、异步的八种实

    2024年02月09日
    浏览(38)
  • Java实现异步的几种方式

    普通线程实现异步,但频繁创建、销毁线程比较耗资源,所以一般交给线程池执行 结果: Future异步 和普通线程实现异步区别不大,只是使用Future是要获取执行后的返回值 结果: Spring的@Async异步 使用@Async注解实现异步的前提是需要在启动类上标注@EnableAsync来开启异步配置

    2024年02月04日
    浏览(70)
  • Java实现Kafka消费者及消息异步回调方式

    Kafka 在创建消费者进行消费数据时,由于可以理解成为是一个kafka 的单独线程,所以在Kafka消费数据时想要在外部对消费到的数据进行业务处理时是获取不到的,所以就需要实现一个消息回调的接口来进行数据的保存及使用。 消息回调接口实现代码如下 Kafka消费者代码实现如

    2024年02月06日
    浏览(54)
  • 面试题2023:Java线程的实现方式

    这是一道频率出现比较高的面试题,像阿里、腾讯、京东的Java初中级工程师面试题都出现过、面试过了薪水也能拿个10K~20K,所以掌握这些基础的知识还是有必要的。 启动线程使用的是start方法,这样会启动一个新的线程,并执行线程的任务。如果直接调用run方法,则可以执

    2023年04月27日
    浏览(33)
  • Java 多线程实现的三种方式

    Java 多线程实现方式主要有三种:继承 Thread 类、实现 Runnable 接口、使用 ExecutorService、Callable、Future 实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。 1、继承 Thread 类实现多线程 继承 Thread 类的方法尽管被我列为一种多线程

    2023年04月27日
    浏览(54)
  • Java 实现多线程的三种方式

    1、三种方法的介绍和比较 1、1三种方式得介绍 1、继承Thread类 2、实现Runnable接口 3、实现Callable接口 1、2三种方法的介绍和比较 1、2、1、实现Runnable接口相比继承Thread类有如下优势 1、增强程序的健壮性,将业务逻辑与线程调度分离 2、线程池只能放入实现Runable或Callable类线程

    2024年02月02日
    浏览(47)
  • 线程方法接收参数示例,Java的两种线程实现方式区别

    总所周知,Java实现多线程有两种方式,分别是继承Thread类和实现Runable接口,那么它们的区别是什么? 继承 Thread 类: 通过继承 Thread 类,你可以创建一个直接表示线程的类。你可以覆盖 Thread 类中的 run 方法来定义线程的逻辑。当调用 start 方法启动线程时,会执行该类中的

    2024年02月11日
    浏览(43)
  • 线程方法接收参数和返回参数,Java的两种线程实现方式对比

    总所周知,Java实现多线程有两种方式,分别是继承Thread类和实现Runable接口,那么它们的区别是什么? 继承 Thread 类: 通过继承 Thread 类,你可以创建一个直接表示线程的类。你可以覆盖 Thread 类中的 run 方法来定义线程的逻辑。当调用 start 方法启动线程时,会执行该类中的

    2024年02月11日
    浏览(45)
  • 如何在Java实现TCP方式发送和接收Socket消息(多线程模式)

    在Java编程中,使用TCP协议进行Socket通信是非常常见的场景。本文将详细介绍如何在Java中实现TCP方式发送和接收Socket消息,并且利用多线程模式来提高通信效率。 首先,我们需要创建一个Server端来处理接收到的Socket连接请求。以下是实现的步骤: 创建一个ServerSocket对象,并指

    2024年02月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包