【Java8新特性】關於並行流與串行流,你必須掌握這些!!


寫在前面

提到Java8,我們不得不說的就是Lambda表達式和Stream API。而在Java8中,對於並行流和串行流同樣做了大量的優化。對於並行流和串行流的知識,也是在面試過程中,經常被問到的知識點。當然,我們不能只是為了應付面試來學習這些知識,更重要的是將這些知識運用到實際的工作中,更好的提高我們的工作效率和工作質量。

什么是並行流?

簡單來說,並行流就是把一個內容分成多個數據塊,並用不同的線程分別處理每個數據塊的流。

Java 8 中將並行進行了優化,我們可以很容易的對數據進行並行操作。 Stream API 可以聲明性地通過 parallel() 與sequential() 在並行流與順序流之間進行切換 。

Fork/Join 框架

Fork/Join 框架: 就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 匯總 。

在這里插入圖片描述

Fork/Join 框架與傳統線程池有啥區別?

采用 “工作竊取”模式(work-stealing):

當執行新的任務時它可以將其拆分成更小的任務執行,並將小任務加到線程隊列中,然后再從一個隨機線程的隊列中偷一個並把它放在自己的隊列中。

相對於一般的線程池實現,fork/join框架的優勢體現在對其中包含的任務的處理方式上。在一般的線程池中,如果一個線程正在執行的任務由於某些原因無法繼續運行,那么該線程會處於等待狀態。而在fork/join框架的實現中,如果某個子任務由於等待另外一個子任務的完成而無法繼續運行。那么處理該子問題的線程會主動尋找其他尚未運行的子任務來執行。這種方式減少了線程的等待時間,提高了程序的性能。

Fork/Join框架實例

了解了ForJoin框架的原理之后,我們就來手動寫一個使用Fork/Join框架實現累加和的示例程序,以幫助讀者更好的理解Fork/Join框架。好了,不廢話了,上代碼,大家通過下面的代碼好好體會下Fork/Join框架的強大。

package io.binghe.concurrency.example.aqs;
 
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
@Slf4j
public class ForkJoinTaskExample extends RecursiveTask<Integer> {
    public static final int threshold = 2;
    private int start;
    private int end;
    public ForkJoinTaskExample(int start, int end) {
        this.start = start;
        this.end = end;
    }
    @Override
    protected Integer compute() {
        int sum = 0;
        //如果任務足夠小就計算任務
        boolean canCompute = (end - start) <= threshold;
        if (canCompute) {
            for (int i = start; i <= end; i++) {
                sum += i;
            }
        } else {
            // 如果任務大於閾值,就分裂成兩個子任務計算
            int middle = (start + end) / 2;
            ForkJoinTaskExample leftTask = new ForkJoinTaskExample(start, middle);
            ForkJoinTaskExample rightTask = new ForkJoinTaskExample(middle + 1, end);
 
            // 執行子任務
            leftTask.fork();
            rightTask.fork();
 
            // 等待任務執行結束合並其結果
            int leftResult = leftTask.join();
            int rightResult = rightTask.join();
 
            // 合並子任務
            sum = leftResult + rightResult;
        }
        return sum;
    }
    public static void main(String[] args) {
        ForkJoinPool forkjoinPool = new ForkJoinPool();
 
        //生成一個計算任務,計算1+2+3+4
        ForkJoinTaskExample task = new ForkJoinTaskExample(1, 100);
 
        //執行一個任務
        Future<Integer> result = forkjoinPool.submit(task);
 
        try {
            log.info("result:{}", result.get());
        } catch (Exception e) {
            log.error("exception", e);
        }
    }
}

Java8中的並行流實例

Java8對並行流進行了大量的優化,並且在開發上也極大的簡化了程序員的工作量,我們只需要使用類似如下的代碼就可以使用Java8中的並行流來處理我們的數據。

LongStream.rangeClosed(0, 10000000L).parallel().reduce(0, Long::sum);

在Java8中如何優雅的切換並行流和串行流呢?

Stream API 可以聲明性地通過 parallel() 與sequential() 在並行流與串行流之間進行切換 。

寫在最后

如果覺得文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公眾號,跟冰河學習Java8新特性。

最后,附上Java8新特性核心知識圖,祝大家在學習Java8新特性時少走彎路。

在這里插入圖片描述


免責聲明!

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



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