轉自 http://cmsblogs.com/?p=1638

共享和可變
要編寫執行緒安全的程式碼,其核心在於對共享的和可變的狀態進行訪問。

“共享”就意味著變數可以被多個執行緒同時訪問。我們知道系統中的資源是有限的,不同的執行緒對資源都是具有著同等的使用權。有限、公平就意味著競爭,競爭就有可能會引發執行緒問題。

“可變”是指變數的值在其生命週期內是可以發生改變的。“可變”對應的是“不可變”。我們知道不可變的物件一定是執行緒安全的,並且永遠也不需要額外的同步(因為一個不可變的物件只要構建正確,其外部可見狀態永遠都不會發生改變)。所以“可變”意味著存線上程不安全的風險。解決辦法:

1、不線上程中共享該狀態變數,可以將變數封裝到方法中。

2、將狀態變數修改為不可變的變數(final)。

3、訪問狀態變數時使用同步策略。

4、使用原子變數類。

執行緒安全性
執行緒安全是一個比較複雜的概念。其核心概念就是正確性。所謂正確性就是某各類的行為與其規範完全一致,即其近似與“所見即所知(we know it when we see it)”。當多個執行緒訪問某各類時,不管執行時環境採用何種排程方式或者這些執行緒將如何交替執行,並且在主調程式碼中不需要任何額外的同步或者協同,這個類都能表現出正確的行為,那麼就稱這個類是執行緒安全的。(引自:《Java併發程式設計實戰》)

執行緒同步
執行緒通過其核心就在於一個“同”。所謂“同”就是協同、協助、配合,“同步”就是協同步調昨,也就是按照預定的先後順序進行執行,即“你先,我等, 你做完,我再做”。

執行緒同步,就是當執行緒發出一個功能呼叫時,在沒有得到結果之前,該呼叫就不會返回,其他執行緒也不能呼叫該方法。就一般而言,我們在說同步、非同步的時候,特指那些需要其他元件來配合或者需要一定時間來完成的任務。在多執行緒程式設計裡面,一些較為敏感的資料時不允許被多個執行緒同時訪問的,使用執行緒同步技術,確保資料在任何時刻最多隻有一個執行緒訪問,保證資料的完整性。

執行緒同步的機制主要有:臨界區、互斥量、事件、訊號量四種方式

1、臨界區:通過對多執行緒的序列化來訪問公共資源或一段程式碼,速度快,適合控制資料訪問。在任意時刻只允許一個執行緒對共享資源進行訪問,如果有多個執行緒試圖訪問公共資源,那麼在有一個執行緒進入後,其他試圖訪問公共資源的執行緒將被掛起,並一直等到進入臨界區的執行緒離開,臨界區在被釋放後,其他執行緒才可以搶佔。

2、互斥量:採用互斥物件機制。 只有擁有互斥物件的執行緒才有訪問公共資源的許可權,因為互斥物件只有一個,所以能保證公共資源不會同時被多個執行緒訪問。互斥不僅能實現同一應用程式的公共資源安全共享,還能實現不同應用程式的公共資源安全共享。

3、訊號量:它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目。

4、事 件: 通過通知操作的方式來保持執行緒的同步,還可以方便實現對多個執行緒的優先順序比較的操作。

【引自:百度百科】

原子性
原子是世界上最小的單位,具有不可分割性。在我們程式設計的世界裡,某個操作如果不可分割我們就稱之為該操作具有原子性。例如:i = 0,這個操作是不可分割的,所以該操作具有原子性。如果某個操作可以分割,那麼該操作就不具備原子性,例如i++。非原子操作都存線上程安全問題,這個時候我們需要使用同步機制來保證這些操作變成原子操作,來確保執行緒安全。

可見性
執行緒可見性是指執行緒之間的可見性,即一個執行緒對狀態的修改對另一個執行緒是可見的,也就是一個執行緒修改的結果,另外一個執行緒立馬就知道了。比如volitile修飾的變數,就具備可見性。

有序性
有序性指的是資料不相關的變數在併發的情況下,實際執行的結果和單執行緒的執行結果是一樣的,不會因為重排序的問題導致結果不可預知。volatile, final, synchronized,顯式鎖都可以保證有序性。