本文主要介绍了Java异步实现的几种方式的总结,具有很好的参考价值,希望对大家有所帮助。如有错误或不足之处,请不吝赐教。
Java 异步实现的几种方式
1. jdk1.8之前的Future
jdk的平行契约中的未来代表了一个未来的结果。当我们向线程池提交一个任务时,我们会返回这个对象,我们可以通过未来得到执行结果。但是jdk1.8之前的未来有点鸡肋,无法实现真正的异步。它需要阻塞来获得结果,或者持续轮询。
通常,我们希望线程在完成一些耗时的任务时,能够自动通知我们结果。可惜原生jdk1.8之前不支持这个,不过我们可以通过第三方库实现真正的异步回调。
/**
* JDK 1.8之前的未来
* @作者管理员
*/
公共类JavaFuture {
公共静态void main(String[] args)引发Throwable,ExecutionException {
ExecutorService executor=executors . newfixedthreadpool(1);
future string f=executor . submit(new callable string(){
@覆盖
公共字符串调用()引发异常{
System.out.println('任务已启动!');
long time method();
System.out.println('任务完成!');
回‘你好’;
}
});
//这里get()方法阻塞了主线程
system . out . println(f . get());
System.out.println(“主线程被阻塞”);
}
}
如果想得到耗时操作的结果,可以通过get()方法得到,但是这个方法会阻塞当前线程。当我们完成一些剩余的工作时,我们可以调用get()方法来尝试获得结果。
还可以调用非阻塞方法isDone来确定操作是否完成,这与下面的过程有些类似:
2. jdk1.8开始的Future
直到jdk1.8才真正支持异步操作,jdk1.8中提供了lambda表达式,让java离函数式语言更近了一步。借助jdk的native CompletableFuture可以实现异步操作,结合lambada表达式可以大大简化代码量。代码示例如下:
包netty _ promise
导入Java . util . concurrent . completablefuture;
import Java . util . concurrent . execution exception;
导入Java . util . concurrent . executorservice;
导入Java . util . concurrent . executors;
导入Java . util . function . supplier;
/**
*基于jdk1.8的任务异步处理
* @作者管理员
*/
公共类JavaPromise {
公共静态void main(String[] args)引发Throwable,ExecutionException {
//两个线程的线程池
ExecutorService executor=executors . newfixedthreadpool(2);
//jdk1.8之前的实现
CompletableFutureString future=completablefuture . supplyasync(new SupplierString(){
@覆盖
公共字符串get() {
System.out.println('任务已启动!');
尝试{
//模拟耗时的操作
long time method();
} catch (InterruptedException e) {
e . printstacktrace();
}
返回“任务完成!”;
}
},执行人);
//采用lambada的实现方式
future . then accept(e-system . out . println(e ' ok '));
System.out.println('主线程正在运行');
}
}
实现类似于下图:
3. Spring的异步方法
先把longTimeMethod封装到Spring的异步方法中,这个异步方法的返回值是Future的一个实例。这个方法必须写在Spring管理的类中。注意@Async。
@服务
公共类异步服务{
@Async
public Future springAsynchronousMethod(){
整数result=long time method();
返回新的AsyncResult(结果);
}
}
其他类调用此方法。这里很重要的一点是,其他类如果在同一个类中调用,是不会生效的。
@自动连线
私有异步服务异步服务;
public void useAsynchronousMethod(){
future future=asynchronous service . spring asynchronous method();
future.get(1000,时间单位。毫秒);
}
实际上,Spring只在原生的Future中封装了一次,我们最终得到的是Future实例。
4. Java如何将异步调用转为同步
换句话说,需要阻塞异步调用,直到获得调用结果。
使用等待和通知方法。
使用条件锁
将来的
使用CountDownLatch
使用循环屏障
五种方法,具体例子见这篇文章。
java异步任务处理
1、场景
最近在做项目的时候遇到了一个小问题:从前台提交到服务器A,服务器B被A调用处理超时。原因是前端曾经请求向db中插入10000个数据,插入后会清空缓存并发送消息。
服务器端有三个操作:A、插入DB b、清理缓存c、发送消息。一万条数据,多说,少说。而且,不仅仅是插入。出现超时现象不奇怪~ ~
2、分析
如何避免超时?一个请求可以处理太多的数据,这些数据可以分成多个请求。每个请求可以处理100条数据,可以有效解决超时问题。为了不影响用户体验,请求改为ajax异步请求。
另外,仔细分析场景。操作A是这个处理的核心,而操作B和C可以异步处理。换句话说,操作A可以在处理后立即返回结果,而不必等待B和C处理完再返回。b和C操作可以在异步任务中处理。
3、实战
(1)执行者服务:任务提交
(2)、演示
异步任务类
公共类执行器演示{
private ExecutorService executor=executors . newfixedthreadpool(1);
public void asynTask()引发InterruptedException {
executor.submit(new Runnable() {
@覆盖
公共无效运行(){
尝试{
thread . sleep(10000);//方便观察结果
} catch (InterruptedException e) {
e . printstacktrace();
}
int sum=0;
for(int I=0;i 1000i ) {
sum=I;
}
system . out . println(sum);
}
});
}
}
客户端模拟
公共类客户端{
公共静态void main(String[] args)引发InterruptedException {
布尔型r=task 2();
如果(r) {
task 3();
}
system . out . println('-main end-');
}
静态布尔task2()引发InterruptedException {
executor demo e=new executor demo();
e . asyntask();
system . out . println('-task 2 end-');
返回true
}
静态void task3()引发InterruptedException {
int j=0;
while(true) {
如果(j 10000) {
打破;
}
}
system . out . println('-task 3 end-');
}
}
原来是酱紫。
-任务2结束-
-任务3结束-
-主端-
499500
我们来分析一下结果。task2是一个异步任务。当它执行到task2时,主线程不会在task2处被阻塞,所以可以执行task3,而不用等待task2完成处理。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。