iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn)之六

線程的風(fēng)險(xiǎn)

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到衢州網(wǎng)站設(shè)計(jì)與衢州網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類(lèi)型包括:成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、空間域名、網(wǎng)頁(yè)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋衢州地區(qū)。

當(dāng)運(yùn)行在一個(gè)多線程環(huán)境中,你總是需要注意一些事情:你不能控制線程執(zhí)行的順序。例如,如果你有兩個(gè)線程,線程1和線程2,CPU可能會(huì)在線程1上運(yùn)行一段時(shí)間,然后又會(huì)切到線程2運(yùn)行一段時(shí)間。問(wèn)題是你不知道CPU何時(shí)切過(guò)去,也不知道會(huì)為一個(gè)線程分配多少時(shí)間。每個(gè)線程運(yùn)行的時(shí)間都不是公平的。

為了演示線程不容易控制帶來(lái)的風(fēng)險(xiǎn),我會(huì)舉一個(gè)例子。這個(gè)例子包括兩個(gè)線程:線程1和線程2. 線程1打印奇數(shù),線程2打印偶數(shù)。這些數(shù)的范圍從1到20. 線程1先啟動(dòng),然后線程2再啟動(dòng)。這個(gè)例子將會(huì)運(yùn)行3次。Listing 6-5 顯示了樣例代碼。

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

正如你看到的,我先調(diào)用打印奇數(shù),然后再打印偶數(shù)。你可能會(huì)期待看到

  • 先打印一些奇數(shù)

  • 奇數(shù)和偶數(shù)平均打印,例如兩個(gè)奇數(shù)和兩個(gè)偶數(shù)

但是,這些猜測(cè)都是不正確的,你可以看表格 6-4, 顯示了3次運(yùn)行的結(jié)果。

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

你看下第2次,0先打印出來(lái),而其他的都是先打印1。奇數(shù)和偶數(shù)打印也不是平均的;而且,也沒(méi)什么跡象表明有多少奇數(shù)在偶數(shù)之前打印。

因此,在多線程環(huán)境中,你不能控制線程執(zhí)行的順序。多線程是一把雙刃劍。開(kāi)發(fā)者實(shí)現(xiàn)一個(gè)多線程應(yīng)用需要注意下面的3個(gè)風(fēng)險(xiǎn)。

  • 安全性:這個(gè)標(biāo)準(zhǔn)意味著在多線程環(huán)境下,輸出要跟預(yù)期的一致。換句話說(shuō),程序可以運(yùn)行在不同的順序中多次,但是最終的輸出必須是可預(yù)見(jiàn)的,正確的?!霸愀獾氖虑椴粫?huì)發(fā)生”。

  • 活躍性:這個(gè)和安全性不同。一種定義是“一些好的情況最終會(huì)發(fā)生”。例如,假設(shè)線程A必須等到線程B的結(jié)果,有時(shí)這些結(jié)果從來(lái)都不返回。因此,線程A從來(lái)不會(huì)計(jì)算最終結(jié)果。這個(gè)通常稱為死鎖。

  • 性能:iPhone應(yīng)用最重要的一個(gè)目標(biāo)就是有一個(gè)比較好的性能和更靈敏的UI。因此,你的性能目標(biāo)必須達(dá)到。活躍性只關(guān)注一些最終發(fā)生的事情;它并不關(guān)心多快獲取到結(jié)果。

我將會(huì)在接下來(lái)的部分使用例子來(lái)涉及到每一個(gè)標(biāo)準(zhǔn),這樣你就可以理解什么樣會(huì)導(dǎo)致一個(gè)不好的結(jié)果,你如何解決它,使得你的應(yīng)用運(yùn)行時(shí)有一個(gè)比較高的性能。

安全性

安全性要求程序運(yùn)行在多線程環(huán)境中,產(chǎn)生一個(gè)正確的期待的結(jié)果,就想他運(yùn)行在單線程環(huán)境中一樣。我會(huì)討論一個(gè)潛在的在多線程環(huán)境中經(jīng)常會(huì)發(fā)生的一個(gè)問(wèn)題,當(dāng)兩個(gè)或多個(gè)線程同時(shí)訪問(wèn)相同的數(shù)據(jù)。

圖 6-5 描述了兩個(gè)線程如何返回一個(gè)相同的item而導(dǎo)致應(yīng)用崩潰。在圖6-5中,線程1嘗試把item push到當(dāng)前棧中。然后,線程2和線程3想要把item取出來(lái),然后檢查確保這個(gè)item在這個(gè)棧中。但是,在兩個(gè)線程檢查之后,線程2先運(yùn)行,然后獲取item。Oops!像你看到的,線程3已經(jīng)沒(méi)有item可以獲取了。這會(huì)導(dǎo)致你的應(yīng)用崩潰。

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

你可以從ThreadSafety工程中獲取到樣例代碼,但是Listing 6-6 顯示了這個(gè)問(wèn)題的代碼注解。注意這個(gè)問(wèn)題不會(huì)總是出現(xiàn),但是如果你運(yùn)行足夠多的時(shí)間,它還是會(huì)發(fā)生的。代碼使用了NSMutableArray變量存儲(chǔ),因此客戶端代碼能夠添加和刪除數(shù)據(jù)。

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

當(dāng)你運(yùn)行上面的代碼一段時(shí)間,你會(huì)收到下面的信息:

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

它告訴你,你嘗試在一個(gè)空的數(shù)組中刪除對(duì)象,這是不應(yīng)該發(fā)生的當(dāng)你在刪除之前已經(jīng)檢查了數(shù)組空的情況。你甚至打印出來(lái)看它是否是最后一個(gè)對(duì)象。

現(xiàn)在,如果你再一次查看圖6-4,你應(yīng)該理解為什么會(huì)崩潰 -- 因?yàn)榈谝粋€(gè)現(xiàn)場(chǎng)檢查和打印出最后一個(gè)對(duì)象后,第一個(gè)線程已經(jīng)停止,而第二個(gè)線程還在運(yùn)行。

解決辦法

對(duì)于這個(gè)問(wèn)題我的解決辦法是鎖住這個(gè)方法直到線程執(zhí)行完。鎖是一種機(jī)制,它能夠確保在一個(gè)時(shí)間內(nèi)只有一個(gè)線程訪問(wèn)一個(gè)指定的代碼塊。想象一下,你現(xiàn)在在一個(gè)比賽中,需要直接和很多人競(jìng)爭(zhēng)。你和你的競(jìng)爭(zhēng)者被問(wèn)了一個(gè)問(wèn)題,而誰(shuí)先響鈴誰(shuí)就能先回答問(wèn)題。在第一個(gè)結(jié)束之后,另外一個(gè)人又可以搖鈴了。當(dāng)?shù)谝粋€(gè)人在回答問(wèn)題時(shí),這個(gè)鈴是被鎖住的。線程也是一樣的。你可以創(chuàng)建一個(gè)鎖,就像是你的鈴一樣:第一個(gè)得到鎖的線程(類(lèi)似搖鈴)會(huì)阻塞其他所有的線程直到它結(jié)束。在第一個(gè)線程結(jié)束之后,鎖就開(kāi)了(類(lèi)似于其他人可以搖鈴了);其他線程能?chē)L試獲取鎖,而這個(gè)過(guò)程可以重復(fù)下去。

鎖機(jī)制的基本概念就是確保當(dāng)一個(gè)線程在執(zhí)行任務(wù)時(shí),其他線程不能打斷。例如,如果線程1獲取到這個(gè)對(duì)象,然后打印出來(lái),線程2必須等到線程1執(zhí)行完才能獲取和從數(shù)組中刪除對(duì)象。

這個(gè)鎖創(chuàng)建在一個(gè)對(duì)象上。如果線程1從對(duì)象A獲取了鎖,其他線程就不能再獲取這個(gè)對(duì)象的鎖了,這些線程必須等待線程1執(zhí)行完后,然后把鎖返回給對(duì)象A。

最簡(jiǎn)單的方式獲取對(duì)象A的鎖的就是使用@synchronized(objA),如下面Listing 6-7 的代碼。

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

注意:在很多情況下,使用self作為鎖,效果是一樣的。你只需要確保你想要鎖住的對(duì)象使用同一個(gè)對(duì)象鎖即可。例如,你有兩個(gè)存儲(chǔ)變量,你可以考慮為每一個(gè)單獨(dú)是有關(guān)一個(gè)鎖。

圖6-6 顯示了@synchronized在線程中是如何工作的。

iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn) 之六

你需要同時(shí)同步push和pop data這兩個(gè)方法,因?yàn)槿绻阒绘i住其中的一個(gè)方法,當(dāng)你pop檢查時(shí),依然會(huì)存在風(fēng)險(xiǎn),還有存儲(chǔ)器push了很多數(shù)據(jù),而你不沒(méi)有按照你想要的方式獲取到對(duì)象。為了防止這些,你需要使用lockObj同時(shí)鎖住他們,這樣在一個(gè)時(shí)間段就只有一個(gè)方法在運(yùn)行。

你的代碼是安全的,但是依然還有兩個(gè)更重要的多線程屬性需要討論。

分享標(biāo)題:iOS使用多線程提高數(shù)據(jù)并發(fā)訪問(wèn)之六
網(wǎng)站路徑:http://muchs.cn/article24/jeppje.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開(kāi)發(fā)、網(wǎng)站設(shè)計(jì)公司網(wǎng)站內(nèi)鏈、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站維護(hù)標(biāo)簽優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

綿陽(yáng)服務(wù)器托管