java並發編程——CompletableFuture


簡介

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 和CompletionStage

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM