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