并發和并行,如何區分?如何使用?
在計算機科學中,“并發”和“并行性”是兩個經常被混淆但實際上具有不同含義的概念。這篇文章,我們將深入探討這兩個概念,并通過Java代碼演示它們的實現。
關于并行和并發, 先看一張很形象的 gif圖片(圖片來自網絡):
接著,我們對照這上面的gif圖來詳細地分析兩者。
1. 并發
(1) 定義
并發性(Concurrency)是指系統能夠處理多個任務,但不一定是同時執行。關鍵在于任務的管理,使得多個任務在時間上交錯進行,以提高資源利用率和響應能力。
如下圖,在一個 CPU上,交替執行多個task:
(2) 特點
- 任務切換:在單核或多核系統上,通過快速切換任務,讓用戶感覺任務是同時進行的。
- 資源共享:多個任務共享系統資源,如CPU、內存等。
- 異步處理:任務可以在等待某些操作完成(如I/O)時,切換到其他任務。
(3) 實際應用示例
- 用戶界面:在圖形用戶界面(GUI)中,主線程負責響應用戶輸入,而后臺線程處理耗時操作,使界面保持響應。
- 服務器處理:Web服務器同時處理多個客戶端請求,通過線程池或異步IO管理并發連接。
(4) Java實現示例
以下是一個簡單的Java并發示例,模擬多個任務交替執行。
public class ConcurrencyExample {
public static void main(String[] args) {
Runnable task1 = () -> {
for(int i=1; i<=5; i++) {
System.out.println("Task1 - Count: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
};
Runnable task2 = () -> {
for(int i=1; i<=5; i++) {
System.out.println("Task2 - Count: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
};
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
}
}
輸出示例(任務交錯執行):
Task1 - Count: 1
Task2 - Count: 1
Task1 - Count: 2
Task2 - Count: 2
...
在這個例子中,兩個任務在同一個處理器上交替執行,實現了并發性。
2. 并行性
(1) 定義
并行性(Parallelism)是指利用多核或多處理器系統同時執行多個任務或任務的多個部分,以加快總體處理速度。
如下圖,多個CPU,每個CPU上分別執行一個 task:
(2) 特點
- 真實的同時執行:在多核處理器上,多個任務可以在不同的核心上同時運行。
- 任務分解:大的任務可以分解為多個子任務,并行處理后合并結果。
- 性能提升:通過并行執行,能夠顯著縮短處理時間,尤其適合計算密集型任務。
(3) 實際應用示例
- 科學計算:數值模擬、天氣預報等需要處理大量數據的應用程序。
- 大數據處理:Hadoop、Spark等框架通過并行計算提高數據處理速度。
(4) Java實現示例
以下是一個使用Java并行流實現并行計算的示例,計算1到1000000的平方和。
import java.util.stream.LongStream;
public class ParallelismExample {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
long sum = LongStream.rangeClosed(1, 1_000_000)
.parallel()
.map(x -> x * x)
.sum();
long endTime = System.currentTimeMillis();
System.out.println("Sum: " + sum);
System.out.println("Time taken: " + (endTime - startTime) + " ms");
}
}
輸出示例:
Sum: 333333833333500000
Time taken: 50 ms
在多核處理器上,.parallel()方法使得流操作并行執行,從而加快計算速度。
3. 并發與并行性的對比
(1) 目標
- 并發性:使多個任務有條不紊地進行,增強系統響應能力和資源利用率。
- 并行性:通過同時執行多個任務,提升總體處理速度和吞吐量。
(2) 示例對比
- 并發:單核處理器上,通過時間片輪轉執行多個任務,使用戶感覺多個任務同時進行。
- 并行:多核處理器上,多個任務或任務的部分在不同核心上同時執行。
(3) 性能考慮
- 并發性適用于I/O密集型應用,通過管理任務等待時間提高系統效率。
- 并行性適用于CPU密集型應用,通過利用多核資源加快計算速度。
(4) 資源利用
- 并發更關注任務的調度和資源的共享。
- 并行更關注如何劃分任務以充分利用多核資源。
4. 通過并發和并行實現的Java框架
在 Java中,提供了豐富的工具和庫來實現并發和并行操作,下面分別舉一個例子來展示并發和并行的實際使用。
(1) 線程和Executor框架
線程是實現并發的基本單元,Java通過Thread類和Runnable接口提供了對線程的支持。但直接使用Thread可能導致資源管理困難,因此Java引入了Executor框架,簡化線程管理。
示例:使用ExecutorService實現并發
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorConcurrencyExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable task1 = () -> {
for(int i=1; i<=5; i++) {
System.out.println("Task1 - Count: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
};
Runnable task2 = () -> {
for(int i=1; i<=5; i++) {
System.out.println("Task2 - Count: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
};
executor.submit(task1);
executor.submit(task2);
executor.shutdown();
}
}
輸出示例:
Task1 - Count: 1
Task2 - Count: 1
Task1 - Count: 2
Task2 - Count: 2
...
(2) 并行流(Parallel Streams)
Java 8引入了Streams API,它支持順序和并行操作,極大簡化了并行處理的編程復雜度。通過調用.parallel(),可以輕松將流操作并行化。
示例:并行處理列表
import java.util.Arrays;
import java.util.List;
public class ParallelStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
numbers.parallelStream()
.map(n -> {
System.out.println("Processing " + n + " in " + Thread.currentThread().getName());
return n * n;
})
.forEach(result -> System.out.println("Result: " + result));
}
}
輸出示例(線程順序可能不同):
Processing 2 in ForkJoinPool.commonPool-worker-1
Result: 4
Processing 1 in ForkJoinPool.commonPool-worker-3
Result: 1
...
5. 實踐建議
- 選擇合適的并發工具:對于簡單的線程管理,可以使用ExecutorService;對于復雜的任務調度,考慮使用ForkJoinPool。
- 避免共享可變狀態:共享狀態可能導致競態條件(Race Conditions),使用線程安全的數據結構或同步機制。
- 理解任務的性質:I/O密集型任務適合并發處理,CPU密集型任務適合并行處理。
- 合理劃分任務:避免過度劃分導致線程切換開銷過大,或任務粒度過粗導致資源浪費。
- 使用高層次抽象:如Java 8的CompletableFuture,簡化異步編程模型。
6. 總結
本文,我們從多個維度對比了并發和并行,雖然在處理多任務方面它們有共同之處,但它們的目標和實現方式不同。并發性側重于任務的管理和調度,以提高系統的響應能力和資源利用率;而并行性則側重于通過同時執行多個任務或任務的多個部分,以提升處理速度和吞吐量。
- 并發性關注的是如何結構化程序以處理多個任務的進展,不一定同時執行。
- 并行性關注的是如何同時執行多個任務,以加快總體的處理速度。