多線程學習總結 day5

---------------------- android培訓java培訓、期待與您交流! ---------------------- 

 每天記錄一點點,進步一點點。。。

一:多線程?

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

線程:就是進程中獨立的空中單元
  線程控制着進程的執行
 一個進程至少有一個線程。
該進程中至少一個線程負責java程序的執行。
而且這個線程運行的代碼存在於main方法中
該線程稱之爲主線程。

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

1.如何在自定義的代碼中,自定義一個線程呢?
通過對api的查找,java已經提供了對線程這類事物的描述,即Thread類
創建線程的第一種方式:繼承Thread類
步驟:
1.定義類繼承Thread

2.複寫Thread 類中的run()方法
 目的:將自定義代碼存儲在run方法中,讓線程運行。

3. 調用線程的start方法
 該方法的兩個作用:啓動線程,調用run()方法。 對象.start();

注意:如果Demo對象直接調用run()方法,而線程創建了,沒有運行,還是主線程在運行。
  start()方法很重要,只有它才能將開啓線程,而run方法僅僅是封裝線程要運行的代碼
  所以在Thread類在描述時,將run和start分開了


因爲運行結果每一次都不同
應爲多個線程獲取cpu的執行權。cpu執行到誰,誰就運行,明確一點,在某一時刻
只能有一個程序在運行(多核除外),cpu 在做着快速的切換,已達到看上去是同時運行的效果
我們可以形象的把多線程的運行行爲在互相強多cpu的執行權

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


二:爲什麼要覆蓋run方法呢?

Thread類用於描述線程。
該類就定義了一個功能,用於存儲線程要運行的代碼。該存儲功能就是run方法
也就是說Thread類中的run方法是用於存儲線程要運行的代碼。
主線程要運行的代碼存放在run方法中,這是java虛擬機定義的,這也是爲什麼虛擬機要調用main方法的原因


三:創建線程的第二種方式?
實現Runnable接口
步驟:
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.必須是多個線程使用同一個鎖。
必須保證同步中只有一個線程在運行。

好處:解決了多線程的安全問題
弊端:如果多個線程執行時,每次都要判斷鎖,較爲消耗資源。

五、鎖?
同步函數用的鎖是this
如果同步函數被靜態修飾後,使用的鎖是什麼呢?
通過驗證,發現不是this。因爲靜態方法中也不一定義this
靜態金內存時,內存中沒有本類對象,但是一定有該類對應的字節碼文件對象。
類名.class 該對象的類型是Class

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

六:單例設計模式?
單例模式有兩種:一種是餓漢式,另一種是懶漢式
有什麼區別(面試):懶漢式的特點在於實例的延遲加載,
懶漢式延遲加載有什麼問題:有,如果多線程訪問時會出現安全問題,怎麼解決,可以加同步來解決。
    可以加同步來解決,用同步代碼塊和同步函數都行,但稍微有些低效,用雙重判斷能解決效率問題
加同步的時候使用的鎖是哪一個:該類所屬的字節碼文件對象。

七:線程間通訊?
其實就是多個線程在操作同一個資源,但操作的動作不同

wait()
notify()
notifyAll()

都使用在同步中,因爲要對持有監視器(鎖)的線程操作
所有要使用在同步中, 以往內只有同步才具有鎖

爲什麼這些操作線程的方法要定義Object 類中呢?
因爲這些方法在操作同步中線程時,都必須要表示他們所操作的線程鎖持有的鎖
只有同一個鎖上的被等待線程,可以被同一個鎖上的notify喚醒,不可以對不同鎖中的線程喚醒

也就是說,等待和喚醒必須是同一個鎖。而鎖可以使任意對象,可以被任意對象調用的方法定義在Object類中

對於多個生產者和消費者。

爲什麼要定義while判斷標記。
原因:讓被喚醒的線程再一次判斷標記

爲什麼定義notifyAll
因爲需要喚醒對象對方線程。
如果只用notify ,容易出現只換醒本方線程的情況。導致程序的所有線程都等待


JDK1.5中提供的多線程的升級解決方案
將同步synchronized 替換成現實Lock操作
將Object中的wait(),notify(), notifyAll(),替換了Condition對象
該對象可以通過Lock鎖進行獲取
一個Lock鎖裏可以綁定多個condition對象;
而synchronized 只能綁定一個鎖對象,是拿鎖來區分
該示例中出現了本方只喚醒對方的操作。

面試:生產者消費者有什麼替代方案?
JDK1.5版本以後提供了顯示的鎖機制,以及的鎖對象上的等待喚醒操作機制,同時把等待喚醒進行了封裝
一個鎖可以對應多個condition對象,沒有升級之前,一個鎖只對應一個wait、notify,想再有一組wait、notify,
         需要再建一個鎖,需要再建一個同步synchronized,一建鎖同步,兩個
         形成嵌套就容易死鎖,現在一個鎖可以對應幾個Condition對象(好幾組wait、notify)

注意:釋放鎖的動作一定要先執行。

八、如何停止線程?
stop方法以及過時,只有一種,run()方法結束。
開啓多線程運行,運行代碼通常是循環結構。
因此,只要控制住循環,就可以讓run()方法結束,也就是線程結束。

特殊情況:
當線程處於了凍結狀態。
就不會讀取到標記。那麼線程就不會結束。

當沒有指定的方式讓凍結的線程恢復到運行狀態時,這時需要對凍結狀態清除,強制讓線程恢復到
運行狀態中來,麼這樣就可以操作標記,讓線程結束。

Thread類提供了該方法 interrupt();

Join:
當A線程執行到了B線程的join方法時,A線程就會等待,等B線程執行完,A線程纔會執行

join可以用來臨時加入線程執行。

先寫到這吧

 ---------------------- android培訓java培訓、期待與您交流! ----------------------詳細請查看:http://edu.csdn.net/heima

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