傳智播客Java自學筆記第11天(待編輯)

----------- android培訓java培訓、java學習型技術博客、期待與您交流! ------------

多線程:

進程:是一個正在執行中的程序。

              每一個進程執行都有一個執行順序。該順序是一個執行路徑,或者叫一個控制單元。

 

線程:就是進程中的一個獨立的控制單元。

              線程在控制着進程的執行。

 

一個進程中至少有一個線程。

 

 

 

Java VM  啓動的時候會有一個進程java.exe.

 

該進程中至少一個線程負責java程序的執行。

而且這個線程運行的代碼存在於main方法中。

該線程稱之爲主線程。

 

擴展:其實更細節說明jvm,jvm啓動不止一個線程,還有負責垃圾回收機制的線程。

 

 

 

1,如何在自定義的代碼中,自定義一個線程呢?

 

通過對api的查找,java已經提供了對線程這類事物的描述。就Thread類。

 

創建線程的第一種方式:繼承Thread類。

步驟:

1,定義類繼承Thread。

2,複寫Thread類中的run方法。

       目的:將自定義代碼存儲在run方法。讓線程運行。

 

3,調用線程的start方法,

       該方法兩個作用:啓動線程,調用run方法。

 

 

 

發現運行結果每一次都不同。

因爲多個線程都獲取cpu的執行權。cpu執行到誰,誰就運行。

明確一點,在某一個時刻,只能有一個程序在運行。(多核除外)

cpu在做着快速的切換,以達到看上去是同時運行的效果。

我們可以形象把多線程的運行行爲在互相搶奪cpu的執行權。

 

這就是多線程的一個特性:隨機性。誰搶到誰執行,至於執行多長,cpu說的算。

 

 

 

爲什麼要覆蓋run方法呢?

 

Thread類用於描述線程。

該類就定義了一個功能,用於存儲線程要運行的代碼。該存儲功能就是run方法。

 

也就是說Thread類中的run方法,用於存儲線程要運行的代碼。

 

創建線程的第二種方式:實現Runable接口

 

步驟:

1,定義類實現Runnable接口

2,覆蓋Runnable接口中的run方法。

       將線程要運行的代碼存放在該run方法中。

 

3,通過Thread類建立線程對象。

4,將Runnable接口的子類對象作爲實際參數傳遞給Thread類的構造函數。

       爲什麼要將Runnable接口的子類對象傳遞給Thread的構造函數。

       因爲,自定義的run方法所屬的對象是Runnable接口的子類對象。

       所以要讓線程去指定指定對象的run方法。就必須明確該run方法所屬對象。

 

 

5,調用Thread類的start方法開啓線程並調用Runnable接口子類的run方法。

 

 

 

實現方式和繼承方式有什麼區別呢?

 

實現方式好處:避免了單繼承的侷限性。

在定義線程時,建立使用實現方式。

 

兩種方式區別:

繼承Thread:線程代碼存放Thread子類run方法中。

實現Runnable,線程代碼存在接口的子類的run方法。

 

多線程的運行出現了安全問題。

 

問題的原因:

       當多條語句在操作同一個線程共享數據時,一個線程對多條語句只執行了一部分,還沒有執行完,

       另一個線程參與進來執行。導致共享數據的錯誤。

 

解決辦法:

       對多條操作共享數據的語句,只能讓一個線程都執行完。在執行過程中,其他線程不可以參與執行。

 

 

 

Java對於多線程的安全問題提供了專業的解決方式。

 

就是同步代碼塊。

 

synchronized(對象)

{

       需要被同步的代碼

 

}

對象如同鎖。持有鎖的線程可以在同步中執行。

沒有持有鎖的線程即使獲取cpu的執行權,也進不去,因爲沒有獲取鎖。

 

火車上的衛生間---經典。

 

同步的前提:

1,必須要有兩個或者兩個以上的線程。

2,必須是多個線程使用同一個鎖。

 

必須保證同步中只能有一個線程在運行。

 

 

好處:解決了多線程的安全問題。

 

弊端:多個線程需要判斷鎖,較爲消耗資源,

 

如何找問題:

1,明確哪些代碼是多線程運行代碼。

2,明確共享數據。

3,明確多線程運行代碼中哪些語句是操作共享數據的。

 

同步函數用的是哪一個鎖呢?

函數需要被對象調用。那麼函數都有一個所屬對象引用。就是this。

所以同步函數使用的鎖是this。

 

靜態同步函數使用的鎖

 

靜態進內存是,內存中沒有本類對象,但是一定有該類對應的字節碼文件對象。

類名.class  該對象的類型是Class

 

靜態的同步方法,使用的鎖是該方法所在類的字節碼文件對象。類名.class

 

等待喚醒機制

       如Input一個,我Output一個。傳進一個,輸出一個。

       在傳進之前,我需要等待數據傳入,傳入完畢後之後,我需要喚醒線程,進行輸出,同時傳入等待輸出完畢之後,才喚醒。

 

都使用在同步中,因爲要對持有監視器(鎖)的線程操作。

所以要使用在同步中,因爲只有同步才具有鎖。

 

爲什麼這些操作線程的方法要定義Object類中呢?

因爲這些方法在操作同步中線程時,都必須要標識它們所操作線程只有的鎖,

只有同一個鎖上的被等待線程,可以被同一個鎖上notify喚醒。

不可以對不同鎖中的線程進行喚醒。

 

也就是說,等待和喚醒必須是同一個鎖。

 

而鎖可以是任意對象,所以可以被任意對象調用的方法定義Object類中。

 

JDK1.5 中提供了多線程升級解決方案。

將同步Synchronized替換成現實Lock操作。

將Object中的wait,notify notifyAll,替換了Condition對象。

 

Lock:替代了Synchronized

       lock

       unlock

       newCondition()

 

Condition:替代了Object wait notify notifyAll

       await();

       signal();

       signalAll();

 

如何停止線程?

只有一種,run方法結束。

開啓多線程運行,運行代碼通常是循環結構。

 

只要控制住循環,就可以讓run方法結束,也就是線程結束。

 

 

特殊情況:

當線程處於了凍結狀態。

就不會讀取到標記。那麼線程就不會結束。

 

當沒有指定的方式讓凍結的線程恢復到運行狀態是,這時需要對凍結進行清除。

強制讓線程恢復到運行狀態中來。這樣就可以操作標記讓線程結束。

 

Thread類提供該方法 interrupt();

----------- android培訓java培訓、java學習型技術博客、期待與您交流! 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章