Java 异步实现的几种方式小结
作者:Amber揣手手 发布时间:2022-09-23 00:26:56
Java 异步实现的几种方式
1. jdk1.8之前的Future
jdk并发包里的Future代表了未来的某个结果,当我们向线程池中提交任务的时候会返回该对象,可以通过future获得执行的结果,但是jdk1.8之前的Future有点鸡肋,并不能实现真正的异步,需要阻塞的获取结果,或者不断的轮询。
通常我们希望当线程执行完一些耗时的任务后,能够自动的通知我们结果,很遗憾这在原生jdk1.8之前是不支持的,但是我们可以通过第三方的库实现真正的异步回调。
/**
* jdk1.8之前的Future
* @author Administrator
*/
public class JavaFuture {
public static void main(String[] args) throws Throwable, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> f = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("task started!");
longTimeMethod();
System.out.println("task finished!");
return "hello";
}
});
//此处get()方法阻塞main线程
System.out.println(f.get());
System.out.println("main thread is blocked");
}
}
如果想获得耗时操作的结果,可以通过get()方法获取,但是该方法会阻塞当前线程,我们可以在做完剩下的某些工作的时候调用get()方法试图去获取结果。
也可以调用非阻塞的方法isDone来确定操作是否完成,isDone这种方式有点儿类似下面的过程:
2. jdk1.8开始的Future
直到jdk1.8才算真正支持了异步操作,jdk1.8中提供了lambda表达式,使得java向函数式语言又靠近了一步。借助jdk原生的CompletableFuture可以实现异步的操作,同时结合lambada表达式大大简化了代码量。代码例子如下:
package netty_promise;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;
/**
* 基于jdk1.8实现任务异步处理
* @author Administrator
*/
public class JavaPromise {
public static void main(String[] args) throws Throwable, ExecutionException {
// 两个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
//jdk1.8之前的实现方式
CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
System.out.println("task started!");
try {
//模拟耗时操作
longTimeMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
return "task finished!";
}
}, executor);
//采用lambada的实现方式
future.thenAccept(e -> System.out.println(e + " ok"));
System.out.println("main thread is running");
}
}
实现方式类似下图:
3. Spring的异步方法
先把longTimeMethod 封装到Spring的异步方法中,这个异步方法的返回值是Future的实例。这个方法一定要写在Spring管理的类中,注意注解@Async。
@Service
public class AsynchronousService{
@Async
public Future springAsynchronousMethod(){
Integer result = longTimeMethod();
return new AsyncResult(result);
}
}
其他类调用这个方法。这里注意,一定要其他的类,如果在同类中调用,是不生效的。
@Autowired
private AsynchronousService asynchronousService;
public void useAsynchronousMethod(){
Future future = asynchronousService.springAsynchronousMethod();
future.get(1000, TimeUnit.MILLISECONDS);
}
其实Spring只不过在原生的Future中进行了一次封装,我们最终获得的还是Future实例。
4. Java如何将异步调用转为同步
换句话说,就是需要在异步调用过程中,持续阻塞至获得调用结果。
使用wait和notify方法
使用条件锁
Future
使用CountDownLatch
使用CyclicBarrier
五种方法,具体举例说明看这篇文章
java异步任务处理
1、场景
最近做项目的时候遇到了一个小问题:从前台提交到服务端A,A调用服务端B处理超时,原因是前端一次请求往db插1万数据,插完之后会去清理缓存、发送消息。
服务端的有三个操作 a、插DB b、清理cache c、发送消息。1万条数据,说多不多,说少不少.况且不是单单insert。出现超时现象,不足为奇了吧~~
2、分析
如何避免超时呢?一次请求处理辣么多数据,可分多次请求处理,每次请求处理100条数据,可以有效解决超时问题. 为了不影响用户的体验,请求改为ajax 异步请求。
除此之外,仔细分析下场景. a 操作是本次处理的核心. 而b、c操作可以异步处理。换句话说,a操作处理完可以马上返回给结果, 不必等b、c处理完再返回。b、c操作可以放在一个异步任务去处理。
3、实战
(1)、ExecutorService : 任务提交
(2)、demo
异步任务类
public class ExecutorDemo {
private ExecutorService executor = Executors.newFixedThreadPool(1);
public void asynTask() throws InterruptedException {
executor.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);//方便观察结果
} catch (InterruptedException e) {
e.printStackTrace();
}
int sum = 0;
for(int i = 0; i < 1000; i++) {
sum += i;
}
System.out.println(sum);
}
});
}
}
客户端模拟
public class Client {
public static void main(String[] args) throws InterruptedException {
boolean r = task2();
if(r) {
task3();
}
System.out.println("------------main end-----------");
}
static boolean task2() throws InterruptedException {
ExecutorDemo e = new ExecutorDemo();
e.asynTask();
System.out.println("------------task2 end-----------");
return true;
}
static void task3() throws InterruptedException {
int j = 0;
while(true) {
if(j++ > 10000) {
break;
}
}
System.out.println("------------task3 end-----------");
}
}
结果是酱紫的
------------task2 end-----------
------------task3 end-----------
------------main end-----------
499500
我们来分析下结果, task2是个异步任务,执行到task2,主线程不会在task2 阻塞,不用等待task2 处理完,可以往下执行task3.
来源:https://blog.csdn.net/weixin_43525116/article/details/85698872


猜你喜欢
- if语句一个if语句包含一个布尔表达式和一条或多条语句。语法If语句的用语法如下:if(布尔表达式){ //如果布尔
- 最近开发项目中,有个在屏幕上任意拖动的悬浮窗功能,其实就是利用 WindowManager的api来完成这个需求,具体的实现的功能如下:1.
- 发送邮件在web开发中,发送邮件是一个很常用的功能,Spring Boot也集成了发送邮件的功能基本使用使用Spring Boot的发送邮件
- 一、背景项目中肯定会遇到异步调用其他方法的场景,比如有个计算过程,需要计算很多个指标的值,但是每个指标计算的效率快慢不同,如果采用同步执行的
- 在Unity开发中捕捉Android的常用事件其实很简单Input.GetKey(KeyCode.Escape) Input.G
- 1、WinForm中datagridview增加行号在界面上拖一个控件dataGridView1,在datagridview添加行事件中添加
- 职责链模式简介及UML职责链也叫责任链,他是一种行为型模式,它为请求创建了一个接收请求者对象的链,并将请求沿着这条链传递到目标对象去处理。该
- zip 是一个非常常见的压缩包格式,本文主要用于说明如何使用代码 文件或文件夹压缩为 zip压缩包及其解压操作,我们采用的是 微软官方的实现
- 配置AOPAOP简介要介绍面向切面变成(Aspect-Oriented Programming,AOP),需要先考虑一个这样的场景:公司有一
- 本文实例讲述了C#判断密码强度的方法。分享给大家供大家参考。具体如下:1.关于密码强度密码强度有强弱之分,包含数字、字母和其他符号三者且长度
- Java类加载器1、BootClassLoader: 用于加载Android Framework层class文件。2、PathClassLo
- mybatis 运行时加载自定义mapper文件用mybatis一定要写mapper文件,这是使用mybatis的常识,但有时候应用需求,m
- 公司的项目底层,是使用的TCP,因为可靠,自动断线重连,在底层都实现了,但是我记得TCP也会有掉包的问题,所以这文章就诞生了——关于TCP掉
- asp.net是没有直接选取文件夹的控件的,我也不知道,如果大家有的话可以一起交流下。后来我想着应该有三种方法:①先将文件夹压缩后上传服务器
- 本文实例讲述了C++语言实现线性表之链表实现方法。分享给大家供大家参考。具体分析如下:插入、删除结点的代码有点多,但这样提高了代码的可读性,
- Android WebView或手机浏览器打开连接问题解决办法总结1.通常情况下 大家可能都想使用WebView打开网页内部链接而不想再调用
- FROM子句一、简单FROM子句获取数据源:var queryAllCustomers = &nb
- 首先,想要明白hashCode的作用,你必须要先知道Java中的集合。 总的来说,Java中的集合(Collection)有两类,一类是Li
- 问题 @Cacheable注解不支持配置过期时间,所有需要通过配置CacheManneg来配置默认的过期时间和针对每个类或者是方法进行缓存
- 导入redis的jar包<!-- redis --> <dependency>