標籤:
1.多線程
1.1.進程與線程
? 進程就是一個運行中的程式。
? 一個進程中可以有多個線程,線程是CPU調度和指派的基本單位。我們可以理解為線程就是程式運行中的一條路徑。
1.2.多線程的建立及使用
1.2.1.建立
自訂一個類繼承Thread類或實現Runnable介面
1.2.2:兩種建立多線程的區別
繼承Thread類:Thread()或Thread(String name) 多個線程分別完成自己的任務
實現Runnable介面:Thread(Runnable target) 或Thread(Runnable target, String name) 是多個線程共同完成一個任務
1.2.3:線程的啟動
? 兩種建立方式都是調用Thread對象的start()方法。當調用start()方法時,CPU會開啟一條新線程,並在新線程上執行run()方法。
1.2.4:線程常用方法
? currentThread:靜態方法,用來擷取當前線程
? getName、setName:用來擷取、設定當前線程的名字
? sleep:控制線程休眠,單位為毫秒
? setDaemon:將線程設定為守護線程。線程預設是非守護線程,守護線程不能單獨執行。
? join:當前線程暫停,等待加入的線程運行結束,當前線程繼續執行。
1.3:線程的同步:
? 同步代碼塊synchronized(鎖對象){需要同步的代碼...}形式將訪問資料的代碼鎖住,在同步代碼塊中的內容同一時間內只能一個線程執行。
方法鎖:如:public synchronized void testSyn(){}。同步非靜態方法使用this作為鎖,靜態方法使用的是類對象本身
1.4:線程的生命週期:
1.建立狀態(New):用new語句建立的線程對象處於建立狀態,此時它和其它的java對象一樣,僅僅在堆中被分配了記憶體
2.就緒狀態(Runnable):當一個線程建立了以後,其他的線程調用了它的start()方法,該線程就進入了就緒狀態。處於這個狀態的 線程位於可運行池中,等待獲得CPU的使用權
3.運行狀態(Running): 處於這個狀態的線程佔用CPU,執行程式的代碼
4.阻塞狀態(Blocked): 當線程處於阻塞狀態時,java虛擬機器不會給線程分配CPU,直到線程重新進入就緒狀態,它才有機會轉到 運行狀態。
阻塞狀態分為三種情況:
1)、 位於對象等待池中的阻塞狀態:當線程運行時,如果執行了某個對象的wait()方法,java虛擬機器就回把線程放到這個對象的等待池中
2)、 位於對象鎖中的阻塞狀態,當線程處於運行狀態時,試圖獲得某個對象的同步鎖時,如果該對象的同步鎖已經被其他的線程佔用,JVM就會把這個線程放到這個對象的瑣池中。
3)、 其它的阻塞狀態:當前線程執行了sleep()方法,或者調用了其它線程的join()方法,或者發出了I/O請求時,就會進入這個狀態中。
1.:5:多線程間的通訊:
在同步代碼中可以使用鎖對象的wait()方法讓當前線程等待
使用鎖對象的notify()方法可以將正在等待的線程喚醒
? 如果多個線程都在等待,notify()喚醒隨機1個
?notifyAll()方法可以喚醒所有在等待的線程
2.鎖機制
3.記憶體的的可見度:
3.1.共用變數線上程間的可見度
共用變數:如果一個變數在多個線程的工作記憶體中都存在副本,那麼這個變數就是這幾個線程的共用變數。
可見度:一個線程對共用變數值的修改,能夠及時地被其他線程看到。
Java記憶體模型(JMM:Java Memory Model():描述了java程式中各種變數的訪問規則,以及在jvm中將變數儲存到記憶體和從記憶體中讀取變數這樣的底層細節。
所有的變數都儲存在主線程中
每個線程都有自己獨立的工作記憶體,裡面儲存該線程使用的變數的副本(主記憶體中該變數的一份拷貝)
特點:1.線程對共用變數的所有操作都必須在自己的工作記憶體中進行,不能直接從主記憶體中讀寫
2.不同線程之間無法直接存取其他線程工作記憶體中的變數,線程間變數值的傳遞需要通過主記憶體來完成。
2.2.java語言層面支援的可見度實現方式(synchronized、volatile):
3.2.1:指令重排序:代碼書寫的順序與實際執行的順序不同,指令的重排序是編譯器或處理器為了提高程式效能而做的最佳化
2.1:編譯器最佳化的重排序(編譯器最佳化)
2.2:指令級並行重排序(處理器最佳化)
2.3:記憶體系統的重排序(處理器最佳化)
3.2:as-if-serial語義:無論如何重排序,程式執行的結果應該與代碼順序執行的結果一致
1. jvm編譯器,運行時和處理器都會保證java在單線程下遵循as-if-serial語義
2.
3.2.3:synchronized實現可見度
3.2.3.1:特性:原子性、可見度
3.2.3.2:線程解鎖前,必須把共用變數的最新值重新整理到主記憶體中,線程加鎖時,將清空工作記憶體中共用變數的值
3.2.3.3:線程執行互斥代碼過程:
1.擷取互斥鎖;
2.清空工作記憶體;
3.從主記憶體拷貝變數的最新副本到工作記憶體;
4.執行代碼;
5把共用變數的最新值重新整理到主記憶體中;
6釋放互斥鎖
3.2.4:volatile實現可見度
指令重排序
volatile使用注意事項
synchronized與volatile
java基礎及多線程