進程:正在進行的應用程序(靜態(tài))
線程:一個進程中的控制單元,一條執(zhí)行路徑,程序?qū)嶋H執(zhí)行的是線程。
一個CPU只支持一個線程執(zhí)行趟脂,因此單CPU采用隨機性原理(CPU快速切換,哪個線程獲取CPU執(zhí)行權例衍,哪個線程執(zhí)行)
main()就是一個線程昔期,成為主線程,主線程優(yōu)先佛玄,cpu先把時間片給主線程
注:一個進程中所有線程都在該進程的虛擬空間中硼一,使用進程的全局變量和系統(tǒng)資源
什么時候考慮使用多線程?當需要某兩個方法同時進行的時候
創(chuàng)建線程兩種方式
一梦抢、繼承Thread般贼,重寫run()方法
(1)創(chuàng)建線程類對象,調(diào)用start()方法(對象與對象間資源不共享)
二惑申、實現(xiàn)Runnable接口具伍。好處:避免了單繼承的局限
(1)定義類實現(xiàn)Runnable接口
? ? class? Test implements Runable
? (2)重寫接口中run()方法,運行start執(zhí)行的就是run()方法里的內(nèi)容
? (3)創(chuàng)建實現(xiàn)接口類的對象(將需執(zhí)行的任務實例化)
? Test t=new Test()
? (4)通過Thread生成一個線程圈驼,傳入需執(zhí)行任務,調(diào)用start()方法
? Thread t1=new Thread(t)//? Thread t1=new Thread(t望几,"線程名")
Start方法與run方法之間的調(diào)用關系
調(diào)用start()會先創(chuàng)建一個新的線程绩脆,這個線程進行一些初始化工作,然后再由這個線程調(diào)用run()
常用方法:
為什么sleep方法只能try catch異常橄抹,不能throw靴迫?
因為Runnable接口使用的是try? catch? 實現(xiàn)接口的類就不能使用throw了
線程的優(yōu)先級
? ? ? ? 線程的優(yōu)先級分為10種從1 – 10數(shù)越小優(yōu)先級越低數(shù)越大優(yōu)先級越大,優(yōu)先級高低影響時間片的分配楼誓,優(yōu)先級越高分配時間片的概率越大玉锌,反之越小。高優(yōu)先級只能說明這個程序優(yōu)先執(zhí)行
線程禮讓(禮讓)
(static void)Yield();滿足某一個條件的時候讓出當前時間片讓其它線程執(zhí)行(只讓出一次)
線程的加入
(void)Join:先執(zhí)行加入的線程
有線程t1 t2想讓t1執(zhí)行完畢之后再執(zhí)行t2要把t1加入到t2當中疟羹,才能保證t1執(zhí)行完畢之后t2才執(zhí)行
守護線程
setDaemon(boolean on)
在程序當中其它的線程都執(zhí)行完畢之后主守,守護線程不管是否已經(jīng)執(zhí)行完畢都強制結(jié)束
Gc就是一個守護線程:垃圾回收器
線程的生命周期
多線程安全問題(使用線程同步解決)? 沒有安全問題使用線程異步禀倔,效率高
當run()方法體內(nèi)的代碼操作到了成員變量(共享數(shù)據(jù))時,就可能會出現(xiàn)多線程安全問題(線程不同步問題)
多線程安全問題出現(xiàn)的原因
例:總共有100張票参淫,兩個窗口賣票救湖,一窗口賣出第20張票時,正要把票的數(shù)據(jù)打印出來涎才,這時二窗口賣出了第21張票鞋既,這就會導致最后打印出的票是第21張票。(每個窗口就是一個線程)
解決辦法耍铜,少使用成員變量多用局部變量
? ? ? ? 為了解決多線程訪問同一資源而出現(xiàn)的安全問題邑闺,我們可以選擇給會出現(xiàn)安全問題的地方加上互斥鎖synchronized,當某個代碼塊被鎖住棕兼,表明該對象在同一時刻只能由一個線程訪問
1.synchronized(this)? ? //this表示的是當前對象
{? ? ? 被同步的代碼检吆;? }
2. synchronized void? 方法名{? }? ? //默認鎖的是當前對象,不推薦使用 因為方法中可能有一些部分并不需要同步程储,同步的代碼越多效率越低
當鎖住一段代碼的時候蹭沛,鎖的鑰匙只有當前執(zhí)行的代碼有,被鎖住的這一段代碼執(zhí)行完后章鲤,才會把鑰匙給別人
賣票的解決方法:
鎖的問題摊灭,如何確定究竟應該所在什么位置?
啟動的兩個線程操縱的都是銀行類里的Money屬性,所以當?shù)谝粋€線程執(zhí)行完之后败徊,第二個線程操縱的是money+完后的錢帚呼,
而這個時候如果沒有鎖的話,當一個線程執(zhí)行完money+之后皱蹦,另一個線程操縱的是money+后的錢煤杀,當2線程也執(zhí)行money+操作后第一個線程輸出,就會輸出錯誤數(shù)據(jù)沪哺。這個for循環(huán)控制的是每個線程只能執(zhí)行6次沈自,所以鎖加到循環(huán)里,是每循環(huán)一次辜妓,兩個線程都可以操作一次枯途,而如果加到循環(huán)外,就變成了一個線程循環(huán)完六次籍滴,另一個線程再進行
面試題
線程1執(zhí)行時酪夷,另一個線程可以同時執(zhí)行方法m2么?孽惰,當然可以晚岭,鎖只是針對鎖住的代碼
當有讀和寫兩個線程,寫線程應該被同步
死鎖問題
解決辦法:加大鎖的粒度
線程安全對單例模式的影響
對于靜態(tài)方法的的鎖對象是什么勋功?
當前類的字節(jié)碼對應的class類--------類.class;
對于餓漢沒有影響坦报,對于懶漢有影響库说,因為如果不加鎖的話,當兩個線程訪問的時候燎竖,一開始都沒有對象璃弄,所以都想要去創(chuàng)建一個對象,結(jié)果可能會導致兩個線程創(chuàng)建了兩個對象构回,出現(xiàn)線程安全問題夏块。
線程之間的通信
多線程訪問不同資源稱為線程之間的通信
wait notify? 是object的方法
線程交互,當兩個線程操縱的是兩段代碼纤掸,而兩段代碼都操作了同一個資源脐供,如果想要兩段代碼互不影響,就要給兩段代碼加上同一個鎖借跪,使得一段代碼的鎖未釋放的時候政己,另一端代碼不可能執(zhí)行
notify的弊端:隨機喚醒一個被掛起的線程改進? ? ? ? ? notifyAll()喚醒所有被掛起的線程
synchronized的缺陷,多線程進行只讀操作的時候掏愁,也需要一個一個進行降低了效率由此引入lock
Lock替代了之前線程的synchronized代碼塊歇由,以面向?qū)ο蟮姆绞饺ソ鉀Q線程安全的問題,該對象使用起來更加的靈活(使用前要創(chuàng)建對象)
Lock()加鎖
Unlock()解鎖
Condition:替代之前Object對象中waitnotifynotifyAll三個方法果港,也是通過面向?qū)ο蟮姆绞饺ソ鉀Q問題沦泌。
Await掛起
Signal喚醒
SignalAll喚醒所有
如何把不安全的集合轉(zhuǎn)為線程安全的集合
Collections工具類中提供了一系列的把不安全的集合轉(zhuǎn)換為安全集合的方法只需要調(diào)用其方法即可
一個讀一個寫,如果想要寫完再讀需要怎么解決辛掠,需要給讀和寫加一個同一個鎖谢谦,這樣寫的鎖沒釋放,讀就不能解開鎖進行讀操作萝衩,這也就是生產(chǎn)者消費者的問題回挽,只有先生產(chǎn)才可能消費