前言:
隨著多核CPU的迅速普及,越來(lái)越多的程序開(kāi)始使用多線程。使用多線程的優(yōu)點(diǎn)是顯而易見(jiàn)的尖啡,不用占用主線程橄仆,把一些繁瑣的是事情交給多線程去做。這樣不用阻塞UI(更新UI是在主線程)衅斩。這樣帶來(lái)了良好的用戶體驗(yàn)盆顾。但是隨著各種好處,尾隨而來(lái)的就是各種莫名其妙的問(wèn)題(crash畏梆,數(shù)據(jù)不對(duì))等等您宪。那么怎么才能解決這個(gè)問(wèn)題呢。這就是我今天要介紹的線程安全具温。
定義
什么是線程安全蚕涤,我的理解是多線程運(yùn)行的結(jié)果,跟單線程運(yùn)行的結(jié)果是一樣的铣猩,不存在時(shí)序?qū)е碌囊幌盗械腸rash揖铜,數(shù)據(jù)不對(duì)等問(wèn)題。這樣就是線程安全的达皿。
線程安全包含兩個(gè)方面:
- 線程 : 根據(jù)平臺(tái)特性創(chuàng)建的線程
- 安全 : crash 與 數(shù)據(jù)正確
線程在是與你的系統(tǒng)平臺(tái)天吓,以及硬件相關(guān)的。如果你是多核的CPU峦椰,那么你是真正意義上的多線程龄寞。如果你只是單核CPU,那么是由系統(tǒng)根據(jù)一定的調(diào)度算法汤功,把任務(wù)拆分程時(shí)間片物邑,輪流交給CPU去運(yùn)行。
圖解線程安全
第一個(gè)圖是線程不安全的滔金,因?yàn)樗臅r(shí)序是亂的色解,導(dǎo)致結(jié)果很隨機(jī)。
第二圖是線程安全的餐茵,因?yàn)樗挎i保證了讀寫(xiě)的時(shí)序科阎。
所以,歸根到底忿族,即使要是用多線程锣笨,也要保持正確的時(shí)序的。才能到達(dá)正確的結(jié)果道批。
上面只是講了結(jié)果不對(duì)的情況错英,還有一種更可怕的,就是crash屹徘。
舉個(gè)例子:
一個(gè)可變數(shù)組走趋,一個(gè)線程正在遍歷,另一個(gè)線程此時(shí)要向這個(gè)數(shù)組里加入元素。那么簿煌,悲劇發(fā)生了氮唯,程序crash了。這樣的列子在咱們實(shí)際應(yīng)用中很常見(jiàn)姨伟,而且這些問(wèn)題惩琉,一般很難查找。
怎樣做到線程安全
做到線程安全夺荒,就是要保證時(shí)序瞒渠。怎么樣保證正確的時(shí)序呢,我總結(jié)了以下幾點(diǎn)技扼。
-
加鎖伍玖。這個(gè)也許是大多數(shù)程序員都會(huì)想到了。把可變變量加鎖剿吻,把臨界代碼區(qū)加鎖窍箍。就是在各種可能導(dǎo)致線程不安全的地方加上鎖。這樣有一個(gè)壞處丽旅,如果在移動(dòng)端開(kāi)發(fā)椰棘,大量的鎖會(huì)導(dǎo)致程序的性能下降。
加鎖還有幾個(gè)注意的地方榄笙。
1.對(duì)于屬性邪狞,這些快速讀取的變量,可以用自旋鎖茅撞,它的速度很快帆卓。
2.對(duì)于代碼塊,就需要加那些常規(guī)的鎖了米丘。比如ios的 @synchronized鳞疲。
這個(gè)方案一般適用于在代碼設(shè)計(jì)初期,要建立一個(gè)線程安全的類(lèi)蠕蚜。
2.所有的可變操作,統(tǒng)一切回一個(gè)線程(可以是主線程)悔橄。也就是把這些可變的操作靶累,都放到一個(gè)有序的隊(duì)列中,一個(gè)一個(gè)按序執(zhí)行癣疟。比如iOS的GCD挣柬,或者perform,都可以到達(dá)這個(gè)目的睛挚。
這個(gè)方案適用于邪蛔,底層是一個(gè)線程不安全的類(lèi),但是上層需要用多線程扎狱,改變底層的影響面太大侧到,只能在上層保證有序了勃教。
總結(jié):以上所寫(xiě)基本都是在實(shí)際應(yīng)用過(guò)程中的所感。有什么不對(duì)的地方還請(qǐng)指正匠抗。這一片都是一些方法論故源,下一篇我會(huì)用例子具體說(shuō)明。