併發編程-線程基礎

進程和線程的區別
學習線程之前,首先要知道什麼是進程。簡單的理解,一個應用程序就是一個進程,比如開啓一個QQ,微信,騰訊視頻。線程可以說是進程的執行單元,一條執行路徑。線程被包含在進程中,一個進程至少有一個線程,但可以有多個線程。

爲什麼用多線程
爲什麼需要多線程呢?試想一下你的生活,廚房一般都有兩個煤氣竈,你可以使用第一個竈燒水的同時,用第二個竈蒸饅頭,這樣就大大節省了時間,或者說在你洗腳的時候吃飯?例子不太恰當,但就是這個意思。

時間片輪轉機制
在最開始,多線程並不是真正意義上的同時執行,因爲只有一個cpu,cpu只是在做着特別特別特別快的切換,在同一時刻,只能運行一個線程,切換的頻率是非常快的,隨機的,讓你覺得他是在同時執行,但線程特別多的時候就會卡頓。到後來,多核cpu出現,這時候纔是真正的多個線程同時執行。

多線程一定好嘛
合理的運用多線程可以提高效率,比如常見的迅雷(同時下載任務),360(一邊清理磁盤垃圾一邊殺毒)。但cpu核數不夠支撐太多線程的時候,就會出現卡頓,嚴重會宕機,使用多線程時,還要考慮死鎖以及線程安全等問題。

線程的生命週期
image.png
關於這個生命週期,說幾種的都有,不同的書裏說什麼詞的也都有,不過大概意思都是一樣的
1.新建:也就是new了一個線程,重寫了run(),還沒有調用start()方法
2.就緒:調用了start()方法,線程進入就緒狀態,因爲即使調用了start()方法開啓了線程,但在這個時刻,也未必拿到cpu的執行權,但已經具備了執行資格
3.運行:得到了cpu的執行權
4.阻塞:調用了sleep方法或者wait方法,此時線程不具備執行資格和執行權,notify後,線程會重新進入就緒狀態,等待獲取cpu的執行權
5.死亡:方法自然執行結束或調用了結束線程的方法

創建線程
繼承Thread類
實現Runnable接口
實現Callable接口

結束線程
stop() 過時,強制幹掉,resume() 過時 suspend() 過時,搶佔資源
interrupt(),中斷線程,只是一個標記位,將線程標記置爲true,並不強制幹掉線程。需要子線程去判斷標記協作處理
isInterrupt(),判斷線程的標記
interrupted(),靜態方法,將線程標記置爲false

線程擴展方法
run()和start()區別,run方法和正常調用沒區別,都是new對象,然後調用方法,start方法纔是真正開啓線程,而run方法是隻是執行的任務
yield()方法,交出執行權,進入執行資格隊列
setPriority(int i)方法,設置線程優先級,默認5,設置1-10,不代表一定會執行哪個多哪個少
setDeamon(boolean b)守護線程,跟着主線程混,主線程執行完,子線程就結束。注意:子線程裏面的finally塊不一定會被執行
join() 加入線程,線程A裏面執行了線程B.join(),那麼A就需要等待線程B執行完成

synchronized關鍵字
保證原子性和可見性(線程安全),注意對象鎖和類鎖的使用,靜態方法默認就是類鎖。

volatile關鍵字
相當於在內存中共享變量,最輕量級的同步機制,保證變量在內存中的可見性。但是不保證原子性,適合一寫多讀的情況

ThreadLocal
各線程之間不共享變量,用當前線程做鍵,值隨意。提供get set方法,不用手動remove,垃圾回收機制會自動回收。適合每個線程池持有自己的鏈接情況下使用

notify()和notifyAll()
notify調用後,會喚醒等待池中的其中一個線程
notifyAll會喚醒等待池中的所有線程

yield(),sleep(),wait(),notify()對鎖的影響
yield執行後,不釋放鎖
sleep也不釋放鎖
wait調用必須先持有鎖,調用後鎖被釋放
notify調用必須先持有鎖,調用notify本身並不會釋放鎖,而是代碼塊執行完之後釋放鎖

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