Java:Async异步代码的实现方式
创始人
2024-05-30 01:04:50
0

异步的八种实现方式

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

继承Thread

package com.example;public class AsyncThread extends Thread {@Overridepublic 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();@Overridepublic 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 future = executorService.submit(new Callable() {@Overridepublic 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 result1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName());return "success";});CompletableFuture 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依赖


4.0.0org.springframework.bootspring-boot-starter-parent2.7.7 com.exampledemo0.0.1-SNAPSHOTdemoDemo project for Spring Boot1.8org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-devtoolsruntimetrueorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtestorg.springframework.bootspring-boot-maven-pluginorg.projectlomboklombok

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 {/*** 自定义线程池**/@Beanpublic Executor taskExecutor() {//返回可用处理器的Java虚拟机的数量 12int i = Runtime.getRuntime().availableProcessors();System.out.println("系统最大线程数  : " + i);ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//核心线程池大小executor.setCorePoolSize(16);//最大线程数executor.setMaxPoolSize(20);//配置队列容量,默认值为Integer.MAX_VALUEexecutor.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@Overridepublic 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 {@Autowiredprivate 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 {@Async@Overridepublic 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 {@Autowiredprivate ApplicationEventPublisher publisher;@GetMapping("/")public String index() {User user = new User();user.setName("Tom");user.setAge(20);// 发布事件publisher.publishEvent(new AsyncSendEmailEvent(user));return "success";}
}

参考

  • Java实现异步编程的8种方式

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...