標籤:虛擬 cpu 類型 代碼塊 ges 不同 存在 單元 obb
多線程:
實現同時執行的效果,實際上是多個線程在爭搶CPU
可以實現不同功能的同時執行
多線程不一定能夠提高效率,但是可以合理的使用PCU資源
多線程的運行結果是不同的,因為線程在爭搶CPU,這就是多線程的隨機性
概念:
進程(Process):
每一個應用程式都會對應一個進程
正在啟動並執行程式,也就是在記憶體中開闢的記憶體空間
線程(Thread):
負責程式執行的一條執行路徑,也稱為一個執行單元
進程的執行實際上是線程在執行
一個進程至少會有一個線程(Main Thread),主線程執行main函數代碼
當一個進程中有多個線程時,就是多線程程式
任務(Task):
每個線程需要執行的代碼
任務代碼都有其儲存位置
主線程的任務代碼在main函數,記憶體回收線程的任務代碼在finalize函數中
線程是隨著任務的存在而存在,隨著任務的結束而消失
/**
*
* JVM(JAVA 虛擬機器)是不是多線程?
*
* 至少有一個負責正常執行的線程,也就是執行main函數中的代碼----主線程
* 還有一個負責記憶體回收的線程,也就是執行finalize函數中的代碼----記憶體回收線程
*
* **每個對象都可以被回收,回收的功能定義在Object的finalize()方法中
* **運行記憶體回收行程,調用System的gc()方法
*
**/
建立線程的第一種方式:
1 建立一個類繼承Thread
2 重寫Thread類中的run方法
建立線程是為了執行任務
任務代碼必須有儲存位置,run方法就是任務代碼的儲存位置
3 建立子類對象,實際在建立線程
4 啟動線程
主線程的任務代碼在main函數中
子線程的任務代碼在run函數中
**run()方法只是一個普通的方法調用,不具備啟動線程的功能
**start()方法會啟動線程並執行run()中的代碼
**currentThread()方法返回當前的線程對象
/**
*
* 為什麼不能直接建立Thread類,然後調用start方法?
*
* 任務代碼必須寫在run方法中,而Thread類中的run方法沒有實現任何功能,代碼執行沒有結果
* 所以只有繼承Thread類,重寫run方法
*
**/
多線程記憶體:
在棧中為主線程開闢記憶體
多線程不遵循先進後出,每個線程在棧中都有記憶體,誰先獲得CPU,就先執行
當線程執行完自己的任務代碼,線程就從棧中消失
只有所有線程都結束,整個進程才結束
建立線程的第二種方式:
為瞭解決臨界資源的問題,需要使用建立線程的第二種方式
1 建立實現了Runnable介面的子類
2 重寫Runnable介面的run方法
3 建立實現了Runnable介面的子類的對西航
4 建立Thread類的對象,也就是建立線程
5 把實現了Runnable忌口的子類對象作為參數傳遞給Thread的構造方法
**把線程任務進行了描述,也就是物件導向
**實現了線程任務和線程對象的分離,線程執行什麼任務不再重要,只要實現了Runnable介面的子類對象都可以作為參數傳遞給Thread的構造方法
**實現了介面的同時還可以繼承父類
線程的生命週期:
/**
*
* 為什麼建立線程的第二種方式可以解決賣票問題?
*
* 第一種建立線程的方式:線程和線程任務是綁定在一起的,建立4個線程就建立了4份資源
* 第二種建立線程的方式:線程和線程任務進行了分離,只需要建立一個任務,讓4個線程分別去執行
*
**/
synchronized代碼塊的鎖:obj
同步函數的鎖:this
靜態同步函數:
靜態函數進記憶體的時候不存在對象,但是存在其所屬類的位元組碼檔案,屬於Class類型的對象,所以靜態同步函數的鎖是其所屬類的位元組碼檔案對象
避免死結:
容易發生在鎖的嵌套
線程間的通訊:
線程間的任務不同,但是線程操作的資料相同
有共用資料
操作共用資料的代碼超過一句
等待喚醒機制:
wait()notify() notifyAll()
必須用在同步中,因為同步中才有鎖
指明讓持有鎖的線程去等待或被喚醒
等待的線程會放棄鎖
**sleep()方法使線程進入掛起(凍結),人為
**wait()方法進入等待狀態,將線程放入線程池
**notify()方法喚醒線程池中的任意一個線程,允許空喚醒,即沒有要喚醒的對象
**notifyAll()方法喚醒所有線程
/**
*
* wait(),notify(),notifyAall()為什麼定義在Object中?
*
* wait(),notify(),notifyAall()必須用在同步中,因為同步中才有鎖
* 鎖是任意對象,任意對象都可以調用的方法需要定義在Obbject中
*
**/
多線程--MultiThread