在最近的项目中,前台出现了一次500的异常,错误信息是 read time out .也就是说,调用的后台方法执行时间过长,然后在前台等待的时间里,没有方法没有执行结束,没有相应的相应,所以这时候,前后台的连接就断开了.而此次我解决问题选择的方法是在后台使用异步机制.
为什么要使用异步
简单来说,使用异步出于无奈.在同一个线程中,一个函数执行的时间过长,那么后面的函数就只能等着,那么我们就需要另外使用一个线程,将运行时间长的函数放到这个单独的线程中去执行.
java 异步编程
下面介绍两种 java 中的异步编程方式.
Future方式的异步编程
Future 表示未来的某个异步计算的结果, 当我们向线程池提交任务的时候,就会获得这个对象. 然后可以使用 get 方法来获取计算完成的结果,并且只有在计算完成时才能使用.
|
|
可以看到,在这段代码中,我们先定义了一个执行者,他会执行未来的某个函数.然后我们定义了一个Future对象,他的值就是上面的执行者 executor 执行了 call 函数后的返回值.这个call函数中就是我们要执行的运行时间很长的函数.在他之后,这个函数或交给另一个线程去执行,而我们也不用等待这个函数执行完,可以去做一些其他的事情.最后,使用 Future 对象中的get方法,获取函数执行后的返回值.
注意: 这里有可能会抛出一个执行异常,所以我们需要在这里使用try catch来处理一下异常.
CompletableFuture方式的异步编程
首先肯定就有人会问,有了Future,那为什么还要选择CompletableFuture这种异步编程的方式呢?
答案显而易见:Future存在缺陷.
Future虽然实现了异步,但是他缺少通知机制,所以我们并不能知道函数什么时候执行结束.
使用阻塞,在
future.get()的地方等待函数返回结果,但是这样就又成了同步的方式了.使用
isDone来进行轮询判断Future是否执行结束,但这样又会显得很多余,浪费很多的CPU.
有问题必然就要解决,所以就有了我们的 CompletableFuture 的编程方式.
CompletableFuture 这种异步编程的方式是在java8才出现的新的异步编程方式.他解决了一些在Future上存在的问题.使得java完整的实现了非阻塞方式的异步编程.
|
|
这里我们可以看到,我们调用了CompletableFuture中的一个静态方法runAsync()来执行异步代码(这里会默认分配给他一个线程池), 他会返回一个没有返回值的CompletableFuture.
当然, CompletableFuture 当中还有很多的静态方法,可以获取没有返回值的,同样也可以获取有返回值的.这里就不一一介绍了.在最后我会给出链接,读者可自行学习.
总结
虽然我们有异步编程的方式去解决函数执行时间长的问题,但是却不要首先想到这个执行办法,首先还是要看我们的函数时候能够减少数据库的IO操作,然后再去想是否应该使用异步编程.
官方参考:
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html