簡介
Java的java.util.concurrent包中提供了並發相關的接口和類,本文將重點介紹CompletableFuture並發操作類
JDK1.8新增CompletableFuture該類
Class CompletableFuture<T>
java.lang.Object
java.util.concurrent.CompletableFuture<T>
All Implemented Interfaces:
CompletionStage <T>, Future <T>
可見源碼中,CompletableFuture是個泛型類,意味着,肯定有地方能夠傳入或返回所指定的泛型類對象,在java8源碼中
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
volatile Object result; // Either the result or boxed AltResult
volatile Completion stack; // Top of Treiber stack of dependent actions
...//部分源代碼省略
}
在JDK1.8的源碼中,我們看見,在類定義下,最前面兩個代碼,定義了兩個volatile的變量,我們都知道volatile變量,主要有兩個作用
1.保證變量在不同線程之間的可見性,修改該變量系統會及時刷新到主內存,各線程讀取的時候從主內存中讀取;
2.禁止指令重排序,通過內存屏障的方式禁止指令被編譯優化后的重排序。
它所實現的兩個接口:Future
1.Future接口
Future接口,在java多線程編程中用到很多,綜合來看主要有兩個方向上會用到
1.通過另外一個線程運行,並帶返回值,通過future的方式傳回返回值
2.程序在主線程中新建並運行新的線程后,主線程需要拿到結果,可以通過future.get阻塞的方式等待線程運行結束並拿回結果。
2.CompletionStage接口
這個主要提供異步線程任務提交、運行的管理,future主要是異步線程運行結果的管理。
綜合來看CompletableFuture
1.創建任務
由於CompletableFuture中JDK8版本出來的,所以對JDK8有了非常好的支持
runAsync(Runnable)
supplyAsync(Supplier)
等等
2.獲取任務結果
get()方法,獲取返回值的時候,如果任務沒有運行完成,則阻塞並一直等到任務結束並返回結果,而在這中間,如果持有這個completableFutre對象可以通過completableFuture.compleate(T)來手動地將結果返回get,並喚醒調用get()線程,任務線程即使運行完再返回去也接受不到了,因為已經被compleate提前返回結果了。
getNow(T vluaeIfAbsent),當調用此方法的時候,如果任務已經完成,則直接拿到返回值,如果沒有則獲取預設定的值,而線程運行狀態不會發生改變
實例
get和getNow的區別
get阻塞代碼,只到任務運行完成返回結果或者直到有人調用compleate(T)
public static void main(String[] args) {
//通過這種方式來創建一個復雜的Student並返回
CompletableFuture<Student> studentCompletableFuture = CompletableFuture.supplyAsync(() -> {
//為了模擬復雜情行
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Student("yan", 50);
});
//如果任務沒有結束,就調用getNow的話,則返回getNow方法傳入的內容
Student student = studentCompletableFuture.getNow(new Student("wang",20));
System.out.println(student.getAge());//輸出20
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
student = studentCompletableFuture.getNow(new Student("wang",20));
System.out.println(student.getAge());//輸出50
}
get和compleate(T)使用
public static void main(String[] args) {
//通過這種方式來創建一個復雜的Student並返回
CompletableFuture<Student> studentCompletableFuture = CompletableFuture.supplyAsync(() -> {
//為了模擬復雜情行
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我能不能運行到?");
return new Student("yan", 50);
});
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
studentCompletableFuture.complete(new Student("wang", 25));
});
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName());
try {
Student student = studentCompletableFuture.get();
System.out.println(student.getAge());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
try {
Student student = studentCompletableFuture.get();
System.out.println(student.getAge());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
執行輸出結果
ForkJoinPool.commonPool-worker-1
pool-1-thread-1
pool-1-thread-2
25
我能不能運行到?
main
25