java學習總結(四)

java學習總結(四)

——關於線程與鎖

Java的內存模型

之前在回答過程中一直會把JAVA的內存模型和JVM的內存模型弄混淆,那麼在這裏一定需要注意。

Java的內存模型由以下三個部分組成:主內存(進程分配的內存)、工作內存、Java線程。

1、不同線程之間沒有辦法訪問其工作內存的變量。
2、線程之間變量傳遞主要通過主內存來完成。
JAVA內存模型

進程與線程:

程序的一次執行稱作一個進程,而線程,是操作系統調動的基本單位。
1、多進程有利於整個程序的健壯性,但是系統資源開銷較大,相比之下多線程編寫的程序利用併發特點,能很好利用CPU,提高效率。
2、進程有其單獨的內存空間,而各個線程共享同一個主進程的內存空間。因此對於共享變量就存在同步問題需要解決。

幾種進程間的通信方式

(1) 管道(pipe):管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有血緣關係的進程間使用。進程的血緣關係通常指父子進程關係。
(2)有名管道(named pipe):有名管道也是半雙工的通信方式,但是它允許無親緣關係進程間通信。
(3)信號量(semophore):信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它通常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作爲進程間以及同一進程內不同線程之間的同步手段。
(4)消息隊列(message queue):消息隊列是由消息組成的鏈表,存放在內核中 並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少,管道只能承載無格式字節流以及緩衝區大小受限等缺點。
(5)信號(signal):信號是一種比較複雜的通信方式,用於通知接收進程某一事件已經發生。
(6)共享內存(shared memory):共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問,共享內存是最快的IPC方式,它是針對其他進程間的通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號量配合使用,來實現進程間的同步和通信。
(7)套接字(socket):套接口也是一種進程間的通信機制,與其他通信機制不同的是它可以用於不同及間的進程通信。

線程之間的通信

在操作系統中,線程的通信主要分爲兩種:1、共享內存。2、消息傳遞
其次就是一些同步原語,這裏列舉一些python的同步原語,Java也同理:
鎖(lock/release):這兩個原語其中框住的部分和Java中synonymous關鍵字修飾的同步代碼塊相同。
信號量(signal):用於描述競爭的資源。共享變量(資源)消耗時遞減,釋放時增加。生產者——消費者模型就是一個很好的例子。
重入鎖(relock):多次調用acquire()而不會被阻塞,可多次申明對資源的需求。鎖內部有計數器,只有release()和acquire()方法調用次數相同時,纔會真正解鎖。
條件變量(condition):是對於鎖的封裝,和信號量相似,也用於調用競爭資源。當資源狀態不可用時,線程會自動釋放手中的鎖,當生產者產生物品時候,這時線程又會立馬被喚醒。
事件(event):
計時器(timer):可設置等待啓動的時間,在啓動前可調用cancel()方法取消,相當於睡眠。

Java的線程安全

線程安全的實現方法:
1、互斥同步:參見同步原語
2、非阻塞同步:先不加鎖,數據操作衝突時候再進行補償操作。
3、無同步方案:1、可重入代碼。2、線程本地存儲(ThreadLocal):如果一段代碼所需要的數據必須與其它代碼共享,可以看看這些共享數據代碼是否能保證再同一個線程中執行。

我們衡量線程安全一定不要受到時間順序的干擾,要以先行發生原則爲準

Java的線程的實現是通過用戶線程(系統感覺不到線程存在的實現,缺點是完全依賴用戶編程實現細節,任務量大)以及輕量級線程混合實現的。

Java線程的調度由兩種:
1、協同式線程調度:線程之間進行資源的商議。缺點是線程的執行時間得不到有效控制。優點是實現簡單。
2、搶佔式線程調度:雖然可以設置線程的優先級,但是,線程的調度的最終狀態還是取決於操作系統。

守護線程

volatile關鍵字

volatile可以說是Java提供的最輕量級的同步機制。
1、volatile保證變量的可見性。而可見性只是說每次對變量修改完成以後都同步回主存。但並不保證變量的原子性。即一次只有一個線程對變量進行操作。所以其修飾的共享變量在多線程環境中一樣是不安全的
2、禁止指令重排優化。通過內存屏障機制,即在執行命令後,立馬將數據store and write同步到主內存。

鎖優化

重量級鎖
synchronized()
輕量級鎖
偏向鎖
JDK1.6引入,鎖偏向於第一個獲得它的線程。

上述兩種情況都是在假設不存在競爭的情況下,嘗試對共享數據進行操作,如果存在競爭或膨脹爲重量級鎖,主要提高的是有同步但是無競爭的程序性能。
自旋鎖
自旋即進入忙循環。JDK1.6中引入了自適應自旋鎖。避免掛起線程與恢復線程帶來的操作系統的損耗。
鎖粗化
對同一個對象加鎖,會把加鎖的同步範圍擴展(粗化)到整個操作序列的外部。
鎖消除
被檢測到不可能存在共享數據競爭的鎖進行消除。特例:字符串相加。

Java線程狀態:

就緒(new)  運行(runable) 阻塞(blocked) 等待(waiting) 結束(terminate) 

這其中主要要弄清楚阻塞與等待之間的區別,阻塞要等待線程放棄鎖,而等待,則是等待特定的之間或者是被其他線程所喚醒。

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