閑談線程安全問題


一、 什么是線程安全問題?

  談到線程安全,那么程序必然是運行在多線程的環境中才會有這樣的問題。那是不是只要是多線程的應用的代碼都有線程安全問題呢?答案顯然是否定的,比如我們寫的Action就是一個運行在多線程環境中的代碼,web服務器接收到一個http請求就會創建一個Thread來處理請求,但是我們的Action為啥沒有方法都沒有加同步呢?原因是我們的action對象,每次接收到一個http請求(一個Thread),都會重新創建(new)一個新的action對象,就是不同線程使用的action對象是不同的。說完action,我們再說說service吧,如果項目使用了spring,我們都知道spring容器中的對象默認是single(單例),也就是程序中service對象只有一個,那么service對象被不同的線程調用的時候使用的都是一個service對象。所以一般情況下service對象應該是一個無狀態的對象,也就是不包含屬性,如果在某些情況下,你給一個service定義了一個屬性,service方法中對該屬性進行了讀和寫操作,這個時候還要不要考慮線程安全問題呢?答案是非常有必要了!

你定義的這個屬性就是一個被多線程共享的資源,同時多線程有讀寫操作,就有可能(注意是有可能)存在線程安全問題。

  總結一下判斷一個程序存不存在線程安全問題的方法:

  1、 程序運行在多線程環境下嗎?

  2、 多線程是否會共享一個資源並且對這個共享資源有讀和寫操作?

  如果滿足以上兩點那就非常有必要考慮線程安全問題。

  所以上面的代碼就是要考慮線程安全問題了。但是你可能會說為啥我知道可能會有線程安全問題,我卻又沒有做任何同步處理?原因是這樣的,要考慮線程安全問題並不代表一定就有線程安全問題。仿佛有點矛盾。因為我這個業務決定了這里不存在線程安全問題,又或者即使這里發生了線程安全問題,導致的結果是可以預計並且不會對系統產生影響的。所以這里我並沒有做同步控制。所以說是判斷存不存在線程安全問題,還要根據業務特點和發生問題導致的結果來判斷。

二、 如何解決線程安全問題

1、 將對象設置成無狀態的

比如上面的service對象盡量不要設置屬性,那么這個service對象就是無狀態的,多線程使用這個service對象時不存在共享資源問題。

2、 使用局部對象

如果上面的activeTimer是一個方法內的對象那么也不存在線程安全問題,因為多線程調用同一個對象的方式時,方法內的對象是私有的。

3、 如果對象中不得不使用屬性時,比如上面的activeTimer必須要設置成service對象屬性,那么可以考慮使用ThreadLocal包裝屬性,包裝后的activeTimer就是一個線程安全的,ThreadLocal實際上是為每個線程都重現創建一個activeTimer對象,各線程用自己的activeTimer,也就避免了線程安全問題,當然導致各線程修改的activeTimer不被共享,需要根據自己的業務特點使用。

4、 當以上3種辦法都不適合的時候,終極大招出來了,使用線程同步技術。把讀寫共享資源的代碼塊上把鎖,給鎖起來,讓多線程調用這段代碼的時候按順序來訪問,這樣就不存在線程安全了。Java中實現線程同步(互斥)的方法主要有兩種,使用synchronizedlock


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM