標籤:
1. 進程與線程
進程:正在運行中的程式。每個進程擁有自己的一整套變數。
線程:進程中一條執行路徑。線程共用資料。每個線程在棧區中都有自己的執行空間,自己的方法區、自己的變數。
2. 多線程 一個進程中至少有一個線程在運行,當一個進程中出現多個線程時,就稱這個應用程式是多線程應用程式。
線程運行必須要通過類中指定的方法開啟:
start方法。
start方法:1)啟動了線程 2)讓jvm調用了run方法
建立線程的方式:
|--繼承Thread類
步驟: 1. 定義類繼承Thread類; 2. 複寫run方法,將要讓線程啟動並執行代碼都儲存到run方法中; 3. 通過建立Thread類的子類對象,建立線程對象; 4. 調用線程的start方法,開啟線程,並執行run方法。 |
--實現Runnable介面 1. 定義類實現Runnable介面; 2. 覆蓋介面中的run方法(用於封裝線程要啟動並執行代碼); 2. 通過Thread類建立線程,並將實現了Runnable介面的子類對象作為參數傳遞給Thread類的建構函式;
為什麼要傳遞呢?因為要讓線程對象明確要啟動並執行run方法所屬的對象。 3. Thread類對象調用start方法開啟線程。
為什麼要有Runnable介面的出現? 1. 通過繼承Thread類的方式,可以完成多線程的建立。但是如果一個類已經有了自己的父類,就不可以繼承Thread類,因為Java單繼承的局限性。
而實現Runnable介面可以避免單繼承的局限性。 2. 其實是將不同類中需要被多線程執行的代碼進行抽取。將多線程要啟動並執行代碼的位置單獨定義到介面中,為其他類進行功能擴充提供了前提。 所以Thread類在描述線程時,內部定義的run方法,也來自於Runnable介面。
線程運行狀態:
被建立: start()
運行: 具備執行資格,同時具備執行權。
凍結: sleep(time), wait()-notify()喚醒;線程釋放了執行權,同時釋放執行資格。
阻塞:具備執行資格,沒有執行權。
消亡:stop()
3. 多安全執行緒
多安全執行緒問題的原因: 因為cpu的快速切換,哪個線程獲得了cpu的執行權,哪個線程就執行。
1)多個線程在操作共用資料
2)有多條語句對共用資料進行運算
解決安全問題的原理: 只要將操作共用資料的語句在某一時段讓一個線程執行,在執行過程中,其他線程不能進來執行。
4. 線程同步
好處:解決了安全執行緒問題。
弊端:相對降低效能,因為判斷鎖需要消耗資源,產生了死結問題。
定義同步前提: 1)必須要有兩個或兩個以上的線程,才需要同步。 2)多個線程必須保證使用的是同一個鎖。
同步函數:將同步關鍵字定義在函數上,讓函數具備了共同性。 1)同步函數使用的鎖是this鎖。 2)當同步函數被static修飾時,鎖對象是
該類的位元組碼檔案對象:類名.class
同步函數和同步代碼塊的區別?
1. 鎖對象:同步代碼塊使用的鎖可以是任意對象;同步函數分兩種情況。 2. 在一個類中只有一個同步,可以使用同步函數;如果有多同步,必須使用同步代碼塊。
同步死結: 通常只要將同步進行嵌套,就可以看到現象。同步函數中有同步代碼塊,同步代碼塊中有同步函數。
等待喚醒機制:(因為這些方法都需要定義在同步中,所以三個方法都定義在Object類中) wait:將同步中的線程處於凍結狀態,釋放執行權,釋放執行資格。同時將線程Object Storage Service到線程池中。 notify:喚醒線程池中某一個等待線程。 notifyAll:喚醒的是線程池中的所有線程。
wait和sleep區別:
wait(可以指定時間也可以不指定時間;不指定時間只能由對應的notify或者notify喚醒):線程會釋放執行權,而且會釋放鎖。
sleep(必須指定時間,時間到自動從凍結狀態轉成運行狀態):線程會釋放執行權,但不釋放鎖。
Lock介面:將鎖對象封裝成對象來處理
同步是隱式的鎖操作,而Lock對象是顯示的鎖操作,它的出現代替了同步。 Lock介面中沒有直接操作等待喚醒的方法,而是將這些方式單獨封裝到了一個對象中:Condition。
Condition介面:await(), signal(), signalAll()
Java基礎-多線程