原文:http://www.cnblogs.com/ckb58/p/7698813.htmlhtml
1、概述
1. 進程
- 一個正在執行的程序。
- 每一個進程的執行都有一個執行的順序,順序是一個執行路徑,也叫一個控制單元。
2. 線程
- 進程中獨立的控制單元稱爲線程。
- 線程控制進程的執行。
- 進程中只要有一個線程在執行,進程就不會結束。
- 一個進程中至少存在一個線程。
3. 多線程
- Java 虛擬機啓動時,會有一個 java.exe 的執行程序,也就是一個進程。
- 這個進程中至少存在一個線程負責 java 程序的執行,這個線程的運行代碼存在 main 方法中,這個線程稱之爲主線程。
- JVM 啓動時除了執行一個主線程,還會啓動負責垃圾回收機制的線程。
- 在一個進程中有多個線程執行的方式,稱爲多線程。
4. 多線程的意義
- 多線程能讓程序產生同時運行的效果,能夠提升程序執行的效率。
- 例如:
- java.exe 進程執行主程序時,若是程序的代碼很是多,在堆內存中會產生不少對象,而對象調用完後就會變成垃圾。若是垃圾過多的話,可能會致使堆內存出現內存不足的現象,影響程序的運行。這種狀況下,若是隻有一個線程在運行處理的話,程序執行的效率很是低;若是有多個線程在幫助處理的話,程序執行的效率將大大的提升。
- 例如:垃圾回收機制的線程在幫助進行垃圾回收的話,那堆內存空間的釋放將快不少。
5. CPU 運行的原理
1. 繼承
2. 實現
3、區別及狀態
1. 建立方式的區別
- 繼承:線程代碼存儲在 Thread 子類的 run 方法中。
- 實現:線程代碼存儲在 Runnable 子類的 run 方法中。
2. 狀態
- 被建立:等待啓動,調用 start 啓動。
- 運行狀態:具備執行資格和執行權。
- 臨時狀態(阻塞):具備執行資格,但沒有執行權。
- 凍結狀態:遇到 sleep(time) 方法和 wait() 方法時,失去執行資格和執行權;sleep 方法的時間結束或調用 notify() 方法時,得到執行資格,變爲臨時狀態(阻塞)。
- 消亡狀態:調用 stop() 方法或 run 方法結束。
- 注:線程從建立狀態到了運行狀態後,再次調用 start() 方法時,已經沒有任何意義,Java 運行時會提示線程狀態異常。
-
4、安全問題
1. 緣由
- 當多條語句操做同一個線程的共享數據時,一個線程對多條語句只執行了一部分,沒執行完成時,另外的線程參與執行,會致使共享數據的錯誤異常,也就是線程的安全問題。
- 總而言之:
- 線程的隨機性。
- 多個線程訪問出現延遲。
- 注:線程的安全問題在理想狀態下,通常不容易出現,可是一旦出現線程的安全問題,將會對程序軟件形成很是大的影響。
2. 同步
- 對於線程的安全問題,在對多條操做共享數據的語句時,只讓一個線程執行完,再讓下個線程去執行,每條線程在執行的過程當中,其它線程都不能夠參與執行。
- Java 中提供了專業的解決辦法 —— synchronized(同步)。
- 解決的方式:同步代碼塊和同步函數。(均是使用關鍵字 synchronized 實現)
- 同步代碼塊
同步函數
- 前提:
- 必須有兩個或以上的線程;
- 必須是多個線程使用同一個鎖。
- 利與弊:
- 利:解決了多線程的安全問題。
- 弊:多個線程均須要判斷鎖,消耗資源,影響效率。
- 如何尋找多線程的安全問題?
- 明確共享數據;
- 明確哪些代碼是多線程運行的代碼;
- 明確多線程運行的代碼中哪些語句是操做共享數據的。
3. 靜態函數的同步
- 同步函數被靜態所修飾後,使用的同步鎖再也不是 this,由於靜態函數中不能夠定義 this,靜態進入內存時,內存中沒有本類對象,但必定存在類所對應的字節碼文件對象。
- 例如:類名.class(對象的類型是 Class)
- 靜態函數所使用的同步鎖就是所在類的字節碼文件對象。
-
例如:
4. 死鎖
說明:程序卡死,沒法繼續執行。
5、通訊
- 多個線程操做同一個資源,可是操做的動做不相同,就是線程間通訊。
- 同步操做同一個資源
- 問題點:
- wait()、notify()、notifyAll() 用來操做線程的,爲何是定義在 Object 類中呢?
- 這些方法存在於同步中;
- 使用這些方法時必需要有標識所屬的同步鎖;
- 例如:同一個鎖上 wait 的線程,只能被同一個鎖上的 notify 喚醒。
- 鎖能夠是任意的對象,任意對象調用的方法必定要定義在 Object 類中。
- wait() 和 sleep() 有什麼區別呢?
- wait():釋放 CPU 的執行權,釋放同步鎖。
- sleep():釋放 CPU 的執行權,不釋放同步鎖。
- 爲何要定義 notifyAll()?
- 須要喚醒對方線程時,若是隻用 notify(),容易出現只喚醒本方線程的狀況,會致使程序中全部線程都處於等待狀態。
JDK 5 及以上版本中提供了多線程同步鎖的升級解決方案
- 將 synchronized(同步)替換成 Lock,將 Object 類中的 wait()、notify()、notifyAll() 替換成 Condition 對象。
- Condition 對象可經過 Lock(鎖)進行獲取,而且支持多個相關的 Condition 對象。
-
例如:
-
6、線程中止
- JDK 5 以前,中止線程用 stop() 方法,JDK 5 及以上版本中,stop() 方法已過期。
- 線程中止的辦法就是讓 run() 方法結束。
- 啓動多線程運行通常都是使用循環結構的代碼,只需控制循環的條件,就可讓 run() 方法結束,也就是線程中止。
- 說明:只要在主函數或者其它線程中,對標記 flag 賦值 false,就可讓 run() 方法結束,線程中止。
特殊狀況:當線程處於凍結狀態時,沒法讀取到 run() 方法中的代碼,線程就沒法中止。
- 須要對線程的凍結狀態進行清除,強制讓線程恢復運行,Thread 類中提供了 interrupt();
-
例如:
7、什麼狀況須要多線程?
- 某些代碼須要同時執行時,可用單獨的線程封裝,多線程運行執行。
-
例如
8、拓展
- join();
- 臨時加入線程去執行:
- 當 A 線程執行到了 B 線程的 join(); 方法時,A 線程等待,B 線程執行完後,A 線程才繼續執行(此時的 B 線程與其它線程交替執行)。
- setPriority();
- 設置優先級:
- MIN_PRIORITY:最低優先級 1
- MAX_PRIORITY:最高優先級 10
- NORM_PRIORITY:默認優先級
- yield();