如何理解什么是線程安全?
什么是線程安全
線程安全在多線程編程時(shí)是一個(gè)比較重要的概念,我們下先來(lái)看下維基百科是如何定義這個(gè)概念的:
https://en.wikipedia.org/wiki/Thread_safety
- Thread safety is a computer programming concept applicable to multi-threaded code. Thread-safe code only manipulates shared data structures in a manner that ensures that all threads behave properly and fulfill their design specifications without unintended interaction.
 
意思是說(shuō):
線程安全是應(yīng)用于多線程代碼的一種計(jì)算機(jī)編程概念,它確保多個(gè)線程能夠按照程序的設(shè)計(jì)正確的訪問(wèn)共享數(shù)據(jù)結(jié)構(gòu)。
或者再貼近編程語(yǔ)言的角度一點(diǎn)來(lái)講,線程安全指的是同時(shí)最少有兩個(gè)及以上的線程操作共享的數(shù)據(jù)區(qū)域,并且至少有一個(gè)是寫操作。如果你還想不明白,可以去衛(wèi)生間觀察一下,一個(gè)廁位同時(shí)能有幾個(gè)人使用。
線程安全的級(jí)別
線程安全的級(jí)別或者粒度有三種,如下:
(1)線程安全
這種情況下其實(shí)沒(méi)有線程安全問(wèn)題,比如上面的例子中,每個(gè)人都有自己專用的衛(wèi)生間,所以不會(huì)存在競(jìng)爭(zhēng)問(wèn)題。
(2)條件安全
條件安全,顧名思義是有條件的,所有人共用幾個(gè)衛(wèi)生間,搶到資源的就把門關(guān)上,通過(guò)門來(lái)隔離資源,后面的人就在外面等待直到里面的人出來(lái)。
(3)不安全
這種情況下連門都沒(méi)有,所以并不能很好保證資源安全,所以這種情況***不能讓同時(shí)讓多個(gè)人直接使用。
實(shí)現(xiàn)線程安全的方式
大體來(lái)說(shuō)有兩種,首先我們明白安全問(wèn)題來(lái)自于競(jìng)爭(zhēng),沒(méi)有競(jìng)爭(zhēng)就不會(huì)有問(wèn)題。
方式一:
核心思路是避免共享數(shù)據(jù)結(jié)構(gòu),共享狀態(tài)。包括:
(1)使用線程local變量
(2)使用不可變對(duì)象
方式二:
核心思路是共享不可避免,需要通過(guò)條件來(lái)確保按照。包括:
(1)互斥鎖
(2)CAS原子操作
Java語(yǔ)言里面實(shí)現(xiàn)策略
這里以Java語(yǔ)言為例子,上面談到的4種方式,其實(shí)在Java里面都支持,分別對(duì)應(yīng)的解決手段為:
(1)ThreadLocal變量
(2)不可變對(duì)象有String,CopyOnWrite集合類
(3) 互斥鎖包括JDK5之前的內(nèi)置鎖synchronized和JDK5之后的Lock接口
(4) J.U.C里面Atom開(kāi)頭的類
可以看出來(lái)Java里面的處理策略還是比較多的,當(dāng)然不同的策略其實(shí)也有具體的適用場(chǎng)景,此外引入了線程安全和同步手段會(huì)對(duì)代碼的性能造成一定的影響,這一點(diǎn)需要了解。
一般來(lái)說(shuō)避免共享數(shù)據(jù)結(jié)構(gòu)是能夠比較優(yōu)雅的解決并發(fā)問(wèn)題,這種程序?qū)Χ嗑€程更友好,性能也會(huì)更高。比如單機(jī)的ThreadLocal和分布式的Ator模型。這里面不存在競(jìng)爭(zhēng)。其次是不可變變量,多線程操作的都是CopyOnWrite,這也是為什么一些動(dòng)態(tài)編程語(yǔ)言如Scala里面的默認(rèn)數(shù)據(jù)結(jié)構(gòu)大多數(shù)都是不可變的。不可變有不可變的好處,但缺點(diǎn)也是明顯的,如果需要頻繁對(duì)數(shù)據(jù)修改,那么會(huì)創(chuàng)建很多臨時(shí)對(duì)象和占用更多的內(nèi)存。
上面這兩種場(chǎng)景,我們一般稱為無(wú)鎖實(shí)現(xiàn),性能很好。如果避免不了共享數(shù)據(jù),那么接著性能比較好的就是CAS這種原子操作,這種情況下我們一般也稱是無(wú)鎖的,但其實(shí)是利用了操作系統(tǒng)的原子指令來(lái)實(shí)現(xiàn)的,在競(jìng)爭(zhēng)不激烈的場(chǎng)景下性能比較好,一般的編程語(yǔ)言都有封裝好的工具類。如果競(jìng)爭(zhēng)激烈,其實(shí)性能未必比使用互斥鎖高。互斥鎖一般也稱重量級(jí)鎖,需要OS干涉線程的調(diào)度,適合用于競(jìng)爭(zhēng)激烈的場(chǎng)景下,這種方式下線程上下文的交換會(huì)降級(jí)系統(tǒng)的性能,在使用時(shí)需要注意。
線程并發(fā)技能圖譜
多線程編程領(lǐng)域其實(shí)涉及很多計(jì)算機(jī)知識(shí),線程安全只是其中的冰山一角,作為一名技術(shù)人員我們有必要系統(tǒng)的學(xué)習(xí)和攻破并發(fā)編程這一塊,很多人覺(jué)得并發(fā)編程很難,其實(shí)是沒(méi)有掌握系統(tǒng)的學(xué)習(xí)方法,在這里我放出我之前總結(jié)并發(fā)知識(shí)的一張圖譜,供大家參考學(xué)習(xí):
總結(jié)
本文主要介紹了什么是線程安全,及實(shí)現(xiàn)線程安全的一些手段,并結(jié)合Java語(yǔ)言描述了相關(guān)的知識(shí),***又總結(jié)了Java里面并發(fā)學(xué)習(xí)的知識(shí)圖譜,只要把里面所有的內(nèi)容都了解掌握,那么在多線程領(lǐng)域就可以從青銅升級(jí)到王者段位了,不過(guò)學(xué)習(xí)之路,學(xué)無(wú)止境,不能急功近利,一定得重基礎(chǔ),然后循序漸近,日拱一卒,就算慢點(diǎn)也無(wú)妨,堅(jiān)持下去,肯定有所收獲。
















 
 
 















 
 
 
 