Java:Async异步代码的实现方式

简介: Java:Async异步代码的实现方式

异步的八种实现方式

  • 线程Thread
  • Future
  • 异步框架CompletableFuture
  • Spring注解@Async
  • Spring ApplicationEvent事件
  • 消息队列
  • 第三方异步框架,比如Hutool的ThreadUtil
  • Guava异步

继承Thread

package com.example;
public class AsyncThread extends Thread {
    @Override
    public void run() {
        System.out.println("current thread name " + Thread.currentThread().getName());
    }
    public static void main(String[] args) {
        AsyncThread asyncThread = new AsyncThread();
        asyncThread.start();
        // current thread name Thread-0
    }
}

使用线程池

package com.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AsyncThread extends Thread {
    // 线程池
    private static ExecutorService executorService = Executors.newCachedThreadPool();
    @Override
    public void run() {
        System.out.println("current thread name " + Thread.currentThread().getName());
    }
    public static void main(String[] args) {
        executorService.submit(new AsyncThread());
        // current thread name pool-1-thread-1
        // 进程卡住,没有结束
    }
}

Future

可以获取执行结果

package com.example;
import java.util.concurrent.*;
public class FutureTask {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        Future<String> future = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("start");
                Thread.sleep(3000);
                System.out.println("end");
                return "success";
            }
        });
        // 等待任务结束,获取返回值
        String result = future.get();
        System.out.println(result);
    }
}

CompletableFuture

package com.example;
import java.util.concurrent.*;
public class AsyncTask {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> result1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            return "success";
        });
        CompletableFuture<Void> result2 = result1.thenRunAsync(() -> {
            System.out.println(Thread.currentThread().getName());
        });
        System.out.println(result1.get());
        System.out.println(result2.get());
        // 输出结果
        // ForkJoinPool.commonPool-worker-1
        // success
        // ForkJoinPool.commonPool-worker-1
        // null
    }
}

SpringBoot的@Async异步

推荐自定义线程池实现异步

项目结构

$ tree
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── demo
        │               ├── Application.java
        │               ├── config
        │               │   └── TaskPoolConfig.java
        │               ├── controller
        │               │   └── IndexController.java
        │               └── service
        │                   ├── AsyncService.java
        │                   └── impl
        │                       └── AsyncServiceImpl.java
        └── resources
            ├── application.yml
            ├── static
            └── templates

pom.xml依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

TaskPoolConfig.java

package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
 * 线程池参数配置
 **/
@EnableAsync
@Configuration
public class TaskPoolConfig {
    /**
     * 自定义线程池
     **/
    @Bean
    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;
    }
}

AsyncService.java

package com.example.demo.service;
public interface AsyncService {
    void sendEmail();
}

AsyncServiceImpl.java

package com.example.demo.service.impl;
import com.example.demo.service.AsyncService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncServiceImpl implements AsyncService {
    @Async
    @Override
    public void sendEmail() {
        try {
            // 模拟耗时3秒
            Thread.sleep(3 * 1000);
        } catch (Exception e) {
            System.out.println("Email发送异常");
        }
        System.out.println("Email发送成功");
    }
}

IndexController.java

package com.example.demo.controller;
import com.example.demo.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
    @Autowired
    private AsyncService asyncService;
    @GetMapping("/")
    public String index(){
        asyncService.sendEmail();
        return "success";
    }
}

Application.java

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Spring ApplicationEvent事件

基于上一节的异步配置,实现异步事件

$ tree
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── demo
        │               ├── Application.java
        │               ├── config
        │               │   └── TaskPoolConfig.java
        │               ├── controller
        │               │   └── IndexController.java
        │               ├── entity
        │               │   └── User.java
        │               ├── event
        │               │   └── AsyncSendEmailEvent.java
        │               └── listener
        │                   └── AsyncSendEmailListener.java
        └── resources
            ├── application.yml
            ├── static
            └── templates

User.java

package com.example.demo.entity;
import lombok.Data;
@Data
public class User {
    private Integer age;
    private String name;
}

AsyncSendEmailEvent.java

package com.example.demo.event;
import com.example.demo.entity.User;
import org.springframework.context.ApplicationEvent;
/**
 * 自定义事件
 */
public class AsyncSendEmailEvent extends ApplicationEvent {
    private User user;
    public AsyncSendEmailEvent(User user) {
        super(user);
        this.user = user;
    }
    public User getUser() {
        return this.user;
    }
}

AsyncSendEmailListener.java

package com.example.demo.listener;
import com.example.demo.event.AsyncSendEmailEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
 * 事件监听器
 */
@Component
public class AsyncSendEmailListener implements ApplicationListener<AsyncSendEmailEvent> {
    @Async
    @Override
    public void onApplicationEvent(AsyncSendEmailEvent event) {
        System.out.println(event.getUser());
        try {
            Thread.sleep(3 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("邮件发送成功");
    }
}

IndexController.java

package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.event.AsyncSendEmailEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
    @Autowired
    private ApplicationEventPublisher publisher;
    @GetMapping("/")
    public String index() {
        User user = new User();
        user.setName("Tom");
        user.setAge(20);
        // 发布事件
        publisher.publishEvent(new AsyncSendEmailEvent(user));
        return "success";
    }
}

参考

相关文章
|
8月前
|
Java 开发工具
【Azure Storage Account】Java Code访问Storage Account File Share的上传和下载代码示例
本文介绍如何使用Java通过azure-storage-file-share SDK实现Azure文件共享的上传下载。包含依赖引入、客户端创建及完整示例代码,助你快速集成Azure File Share功能。
600 6
|
8月前
|
Java 数据处理 API
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
390 115
|
8月前
|
安全 Java 编译器
为什么你的Java代码需要泛型?类型安全的艺术
为什么你的Java代码需要泛型?类型安全的艺术
288 98
|
8月前
|
Java 编译器 API
java最新版和java8的区别,用代码展示
java最新版和java8的区别,用代码展示
681 43
|
8月前
|
安全 Java 容器
告别空指针噩梦:Optional让Java代码更优雅
告别空指针噩梦:Optional让Java代码更优雅
539 94
|
8月前
|
安全 Java 容器
告别繁琐判空:Optional让你的Java代码更优雅
告别繁琐判空:Optional让你的Java代码更优雅
|
9月前
|
IDE Java 关系型数据库
Java 初学者学习路线(含代码示例)
本教程为Java初学者设计,涵盖基础语法、面向对象、集合、异常处理、文件操作、多线程、JDBC、Servlet及MyBatis等内容,每阶段配核心代码示例,强调动手实践,助你循序渐进掌握Java编程。
1184 3
|
9月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
1094 3
|
9月前
|
Java
java入门代码示例
本文介绍Java入门基础,包含Hello World、变量类型、条件判断、循环及方法定义等核心语法示例,帮助初学者快速掌握Java编程基本结构与逻辑。
681 0