Java併發編程——線程安全及解決機制簡介

簡介:安全

本文主要介紹了Java多線程環境下,可能會出現的問題(線程不安全)以及相應的解決措施。經過本文,你將學習到以下幾塊知識:多線程

1. 爲何須要多線程(多線程的優點)異步

1. 多線程帶來的問題—線程安全性能

2. 產生線程不安全的緣由學習

3. 有哪些方法能解決線程不安全測試

------------------------------------------------------------spa

繫好安全帶,下面進入正文:線程

 

一:爲何須要多線程?設計

線程是Java語言中不可或缺的重要部分,它們能使複雜的異步代碼變得簡單,簡化複雜系統的開發;能充分發揮多處理器系統的強大計算能力。多線程和多進程的區別與選擇能夠參考個人另外一篇博客。調試

(1) 優勢

1. 充分利用硬件資源。因爲線程是cpu的基本調度單位,因此若是是單線程,那麼最多隻能同時在一個處理器上運行,意味着其餘的CPU資源都將被浪費。而多線程能夠同時在多個處理器上運行,只要各個線程間的通訊設計正確,那麼多線程將能充分利用處理器的資源。

2. 結構優雅。多線程程序能將代碼量巨大,複雜的程序分紅一個個簡單的功能模塊,每塊實現複雜程序的一部分單一功能,這將會使得程序的建模,測試更加方便,結構更加清晰,更加優雅。

3. 簡化異步處理。爲了不阻塞,單線程應用程序必須使用非阻塞I/O,這樣的I/O複雜性遠遠高於同步I/O,而且容易出錯。

(2) 缺點

1. 線程安全:因爲統一進程下的多個線程是共享一樣的地址空間和數據的,又因爲線程執行順序的不可預知性,一個線程可能會修改其餘線程正在使用的變量,這一方面是給數據共享帶來了便利;另外一方面,若是處理不當,會產生髒讀,幻讀等問題,好在Java提供了一系列的同步機制來幫助解決這一問題,例如內置鎖。

2. 活躍性問題。可能會發生長時間的等待鎖,甚至是死鎖。

3. 性能問題。 線程的頻繁調度切換會浪費資源,同步機制會致使內存緩衝區的數據無效,以及增長同步流量。

二:線程安全

(1) 定義:當多個線程訪問某個類時,無論運行時環境採用何種調度方式或者這些線程將如何交替運行,而且在主調試代碼中不須要任何額外的同步或者協同,這個類都能表現出正確的行爲,則稱這個類時線程安全的。線程安全類中封裝了必要的同步機制,所以客戶端無須進一步採起同步措施。

(2) 線程安全產生的緣由:正確性取決於多個線程的交替執行時序,產生了競態條件。

(3) 原子類: 應儘可能使用原子類,這樣會讓你分析線程安全時更加方便,但須要注意的是用線程安全類構建的類並不能保證線程安全。例如,一個AtomicInteger get() 和 AtomicInteger set() 是線程安全的,在一個類的一個方法 f()中同時用到了這兩個方法,此時的f()就是線程不安全的,由於你不能保證這個複合操做中的get 和 set同時更新。  

三:解決機制

1. 加鎖。

(1) 鎖能使其保護的代碼以串行的形式來訪問,當給一個複合操做加鎖後,能使其成爲原子操做。一種錯誤的思想是隻要對寫數據的方法加鎖,其實這是錯的,對數據進行操做的全部方法都需加鎖,無論是讀仍是寫。

(2) 加鎖時須要考慮性能問題,不能老是一味地給整個方法加鎖synchronized就了事了,應該將方法中不影響共享狀態且執行時間比較長的代碼分離出去。

(3) 加鎖的含義不單單侷限於互斥,還包括可見性。爲了確保全部線程都能看見最新值,讀操做和寫操做必須使用一樣的鎖對象。

2. 不共享狀態

(1) 無狀態對象: 無狀態對象必定是線程安全的,由於不會影響到其餘線程。

(2) 線程關閉: 僅在單線程環境下使用。

3. 不可變對象

可使用final修飾的對象保證線程安全,因爲final修飾的引用型變量(除String外)不可變是指引用不可變,但其指向的對象是可變的,因此此類必須安全發佈,也即不能對外提供能夠修改final對象的接口。

相關文章
相關標籤/搜索