Java並發編程知識整理
1、什麽是進程、線程、多線程?
進程當一個程序開始運行時,它就是一個進程,進程包括運行中的程序和程序所使用到的內存和系統資源。進程間通訊依靠IPC資源,例如管道、套接字
線程是程序中的一個執行流,每個線程都有自己的專有寄存器(棧指針、程序計數器等),但代碼是共享的,即不同的線程可以執行同樣的函數。
多線程是指程序中包含多個執行流,即在一個程序中可以同時運行多個不同的線程來執行不同的任務,也就是說說允許單個程序創建多個並行執行的線程來完成各自的任務。線程間通訊依靠JVM提供的API,例如wait()、notify、notifyAll等方法,線程間還可以通過共享的主內存來進行值的傳遞
2、多線程的優缺點?
優點:可以提高CPU的利用率。在多線程程序中,一個線程必須等待的時候,CPU可以運行其他的線程而不是等待,提高程序相應效率。
缺點:線程也是程序,所有線程需要占用內存,線程越多占用的內存也越多。
線程需要協調和管理,所以需要CPU時間跟蹤線程
線程之間對共享資源的訪問會互相影響,必須要解決競用共享資源的問題
線程太多會導致控制太復雜,最終可能造成很多Bug
3、多線程一定比單線程快嗎?
不一定,由於多線程會存在線程上下文切換,會導致程序執行速度變慢,但可以充分利用CPU,所以對於用戶來說,可以減少用戶響應時間。
比如,嘗試使用並行和串行分別執行累加的操作觀察是否並行執行一定比串行更快:
package com.test.demo; public class Tester { private static final long count = 1000000000; public static void bingxing() throws Exception { long startTime = System.currentTimeMillis(); //通過匿名內部類來創建線程 Thread thread1 = newThread(new Runnable() { @Override public void run() { int a = 0; for(long i = 0; i < count; i++) { a += 1; } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { int b = 0; for(long k = 0;k < count; k++) { b+=1; } } }); //啟動線程 thread1.start(); thread2.start(); //等待線程結束 thread1.join(); thread2.join(); long time = System.currentTimeMillis() - startTime ; System.out.println("並行花費時長:" + time + "ms"); } public static void chuanxing() { long startTime = System.currentTimeMillis(); int a = 0; for(long i = 0; i < count; i++) { a += i; } int b = 0; for(long k = 0;k < count; k++) { b+=k; } long time = System.currentTimeMillis() - startTime ; System.out.println("串行花費時長:" + time + "ms"); } public static void main(String[] args) throws Exception { bingxing(); chuanxing(); } }
循環次數 | 串行執行/ms | 並行執行/ms | 結果 |
1千 | 0ms | 2ms | 慢 |
1萬 | 0ms | 2ms | 慢 |
10萬 | 3ms | 4ms | 慢 |
100萬 | 6ms | 4ms | 快 |
1000萬 | 13ms | 11ms | 快 |
1億 | 89ms | 78ms | 快 |
從測試結果看出當超過100萬次循環後,並行執行的優勢越加明顯,不超過100萬次循環時,串行執行的速率要比並行執行的速率高,原因就是多線程有上下文切換的開銷。
4、阻塞與非阻塞
阻塞和非阻塞通常用來形容多線程之間的相互影響
阻塞是指一個線程占用了臨界區資源,那麽其他所有需要這個資源的線程就不洗在這個臨界區中進行等待,等待會導致線程掛起,這種情況就是阻塞
非阻塞強調沒有一個線程可以妨礙其他線程執行,所有線程都會嘗試不斷向前執行
5、臨界區
臨界區用來表示一種公共資源或者共享資源可以被多個線程使用,但是每一次只能有一個線程使用它,一旦臨界區資源被占用,其他線程想要使用這個資源,就必須等待
6、死鎖Deadlock、饑餓starvation、活鎖Livelock
死鎖表示兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們將無法推進下去,此時稱系統處於死鎖狀態,這些永遠在互相等待的進程成為死鎖進程
饑餓表示一個或者多個線程應為種種原因無法獲得所需要的資源,導致一直無法執行。導致饑餓的原因可能是該線程優先級太低,而高優先級的線程不但搶占它所需要的資源,導致其無法向前推進,另外一種可能是,某線程一直占著關鍵資源不放,導致其他需要這個資源的線程無法正常執行
活鎖表示兩個或者多個線程主動將資源釋放給其他線程,導致沒有一個線程可以同時拿到所有資源而正常執行。
7、如何避免死鎖
指定獲取鎖的順序
Java並發編程知識整理