巧用CompletableFuture返回值解決性能瓶頸

需求背景

對一組字符串數據進行處理,處理邏輯簡單封裝一個對象,包裝該字符串,最終彙總返回。
下面實現只使用CompleteableFuture,其它方式如paraStream不考慮。

無返回值CompletableFuture實現

考慮到性能,對於字符串的處理可以進行併發。實現如下:

    private static ExecutorService executorService = Executors.newFixedThreadPool(10,
            UserThreadFactory.build("future-test"));

    private List<String> result = new ArrayList<>();
    @Before
    public void init() {
        for (int i = 0; i < 1000; i++) {
            result.add("a" + i);
        }
    }

    @Test
    public void testCompleteFuture1(){
        List<List<String>> partition = Lists.partition(result, 100);
        Vector<AD> vector=new Vector<>();
        List<CompletableFuture<Void>> futures = partition.stream().map(list -> {
            return CompletableFuture.runAsync(() -> {
                for (String s : list) {
                    AD ad = new AD();
                    ad.name = s + "--p";
                    vector.add(ad);
                }
            }, executorService);
        }).collect(toList());
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[]{})).join();
    }

利用了CompletableFuture<Void>進行併發處理,使用線程安全的vector用於匯聚最後的數據。上文的存在的問題是線程安全的vector有鎖導致性能降低,實現應用中邏輯比上述例子複雜,該處成爲了性能瓶頸。

有返回值CompletableFuture實現

使用帶有返回值的completable編碼實現

    public void testCompleteFuture2() {
        List<List<String>> partition = Lists.partition(result, 100);
        List<CompletableFuture<List<AD>>> futures = partition.stream().map(list -> {
            return CompletableFuture.supplyAsync(() -> {
                List<AD> ads = new ArrayList<>();
                for (String s : list) {
                    AD ad = new AD();
                    ad.name = s + "--p";
                    ads.add(ad);
                }
                return ads;
            }, executorService);
        }).collect(toList());
        List<AD> collect = futures.stream().map(p -> {
            try {
                return p.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return null;
        }).filter(Objects::nonNull).flatMap(List::stream).collect(toList());
}

上述的例子則沒了vector鎖的限制,性能上不存在問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章