創(chuàng)建信號量的方式:
成都網(wǎng)站建設(shè)、網(wǎng)站制作的關(guān)注點(diǎn)不是能為您做些什么網(wǎng)站,而是怎么做網(wǎng)站,有沒有做好網(wǎng)站,給創(chuàng)新互聯(lián)建站一個展示的機(jī)會來證明自己,這并不會花費(fèi)您太多時間,或許會給您帶來新的靈感和驚喜。面向用戶友好,注重用戶體驗,一切以用戶為中心。
(1)dispatch_semaphore_creat SignalCount = dispatch_semaphore_creat(10).
這個地方后面的這個10,是一個整數(shù),可以是1,2,3,。。。表示在信號等待的時候,下一次收到的的信號量,說白了,就是這個數(shù)字控制的最大并發(fā)數(shù)。
(2)dispatch_semaphore_signal( ),這是一句表示信號通知。表示在信號等待的時候,收到的下一個信號量。一般是一個“信號量對象”。
(3)dispatch_semaphore_wait(參數(shù)一,參數(shù)二 ),這一句表示信號等待。
一般參數(shù)一會放一個信號對象,就是我們建立的那個,如果這個對列的信號量小于0的時候,就會一直等待下去。
參數(shù)二的值一般是 DISPATCH_TIME_FOREVER 和 DISPATCH_TIME_NOW
下面我們寫一段代碼來說明一下。(注:當(dāng)然是參考別人的)
這個地方,解釋一下,新建一個信號量為10的對象,就是將隊列的最大并發(fā)數(shù)控制在10。
第一次打印的結(jié)果是 0,1,2,3,4,5,6,7,8,9。十個數(shù)字。
最關(guān)鍵的是dispatch_semaphore_signal(semphore),如果打印完第一輪十個數(shù)字,不再進(jìn)行信號通知的話,線程就永遠(yuǎn)阻塞下去咯。剩下的10~99就不會再打印下去。
(注:以上是看了一個大神地思路以后,自己擺弄了一下,然后給大家解釋一下,感謝那位大神,有些公司去面試的時候,會問NSOperation這個類通過調(diào)用setMaxConcurrentOperationCount這個方法設(shè)置最大的并發(fā)數(shù),多線程技術(shù)GCD可以嗎?答案是可以的,還有之前看過另外一個大神的,通過信號量控制,將異步的線程變成同步線程的,有興趣的同學(xué)可以去參閱以下)。
線程和進(jìn)程在我們開發(fā)中,跟我們一直形影不離,那么什么是進(jìn)程,什么是線程,它們又有什么關(guān)系,這篇文章將為您簡單介紹。
線程概念
進(jìn)程概念
地址空間:同?進(jìn)程的線程共享本進(jìn)程的地址空間( TLS是本地的線程棧存空間,線程的局部空間是某些操作系統(tǒng)為線程提供的私有空間,只具備有限的容量,并不屬于線程,由操作系統(tǒng)單獨(dú)安排的 ),?進(jìn)程之間則是獨(dú)?的地址空間。
資源擁有:同?進(jìn)程內(nèi)的線程共享本進(jìn)程的資源如內(nèi)存、I/O、cpu等,但是進(jìn)程之間的資源是獨(dú)?的。
優(yōu)點(diǎn):
缺點(diǎn):
時間?的概念:CPU在多個任務(wù)直接進(jìn)?快速的切換,這個時間間隔就是時間?。
多線程同時執(zhí)行
如果線程非常多
互斥鎖?結(jié)
互斥鎖參數(shù)
nonatomic?原?屬性
atomic原?屬性(線程安全),針對多線程設(shè)計的,默認(rèn)值,保證同?時間只有?個線程能夠?qū)?(但是同?個時間多個線程都可以取值)
atomic本身就有?把鎖(?旋鎖)
單寫多讀:單個線程寫?,多個線程可以讀取
atomic:線程安全,需要消耗?量的資源
nonatomic:?線程安全,適合內(nèi)存?的移動設(shè)備
iOS開發(fā)建議
所有屬性都聲明為nonatomic
盡量避免多線程搶奪同一塊資源
盡量將加鎖,資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器處理,減少APP的壓力
這篇文章簡單介紹了線程與進(jìn)程的概念,煩請大家不吝賜教。
在多線程開發(fā)中,我們常用到GCD,這里探討一下GCD任務(wù)的取消:
1.在iOS 8以后,系統(tǒng)給我們提供了這樣的取消函數(shù) dispatch_block_cancel,不過這個也只能用于dispatch_block_create創(chuàng)建的dispatch_block_t,我們試驗一下:
這時肯定是任務(wù)都會執(zhí)行的
接下來,把注釋的那一行 dispatch_block_cancel(block1);打開,看看效果:
我們發(fā)現(xiàn)block1確實被取消掉了。這是dispatch_block_cancel的用法。
2.很多時候,我們的場景不會去用dispatch_block_create創(chuàng)建dispatch_block_t,這個時候我們?nèi)粝肴∠粋€任務(wù),可以考慮用一個條件來做,滿足條件則執(zhí)行此任務(wù),不滿足則不執(zhí)行,舉個例子:
效果如下:
寫到這里,這兒其實還隱藏了一個知識點(diǎn),就是block的變量捕獲,有興趣或是不理解的朋友可以研究一下。(如下,為何輸出不是20而是10)
3.過渡到NSOperation
NSOperation是對GCD的封裝,底層也是GCD。
NSOperation給我們封裝了更多的api,這是我在Xcode中提出來的:
我們可以發(fā)現(xiàn)它有狀態(tài)屬性,有取消方法,也有添加依賴方法等...這里我們還是先說取消吧,下面來給大家寫個demo:
這時輸出是:
因為正在執(zhí)行的任務(wù),NSOperation也是不能取消的,所以也是需要將cancel在start前調(diào)用的(就如同滿足一個條件是否需要cancel一樣,也可以滿足條件不調(diào)用start)
概念:隊列只負(fù)責(zé)任務(wù)的調(diào)度,而不負(fù)責(zé)任務(wù)的執(zhí)行,任務(wù)是在線程中執(zhí)行的。(可以理解成任務(wù)是放在隊列里面的,要被調(diào)度到線程中去執(zhí)行)
特點(diǎn):隊列先進(jìn)先出,排在前面的任務(wù)最先執(zhí)行。
分類:隊列分為串行、并行、主隊列、全局隊列。
任務(wù)的執(zhí)行是在線程上去執(zhí)行的。分為同步和異步。
所以就可以分成:串行隊列同步執(zhí)行、串行隊列異步執(zhí)行、并行隊列同步執(zhí)行、并行隊列異步執(zhí)行。
GCD實現(xiàn)原理:
GCD有一個底層線程池,這個池中存放的是一個個的線程。之所以稱為“池”,是因為這個“池”中的線程是可以重用的,當(dāng)一段時間后沒有任務(wù)在這個線程上執(zhí)行的話,這個線程就會被銷毀。注意:開多少條線程是由底層線程池決定的(線程建議控制再3~5條),池是系統(tǒng)自動來維護(hù),不需要我們程序員來維護(hù)。
我們只關(guān)心的是向隊列中添加任務(wù),隊列調(diào)度即可。
定義:調(diào)用方法(viewDidLoad)的隊列(主隊列)恰好是同步操作(dispatch_sync)所針對的隊列(dispatch_get_main_queue)。
示例1:
輸出結(jié)果:
dispatch_sync 和 dispatch_async 區(qū)別:
dispatch_async(queue,block) async 異步隊列,dispatch_async 函數(shù)會立即返回, block會在后臺異步執(zhí)行。
dispatch_sync(queue,block) sync 同步隊列,dispatch_sync 函數(shù)不會立即返回,及阻塞當(dāng)前線程,等待 block同步執(zhí)行完成。
以上例子就會死鎖,因為viewDidLoad的這個任務(wù)是被主隊列調(diào)用的的,而dispatch_sync不會立即返回,而是先阻塞當(dāng)前的主線程,直到這個block執(zhí)行完畢,因為主線程被阻礙了,啥也干不了了(只有一個線程還被阻塞了,就會造成死鎖),所以這個block就永遠(yuǎn)沒有機(jī)會執(zhí)行了,所以就會造成死鎖。
示例2:
輸出結(jié)果:
示例2就不會造成死鎖,因為dispatch_async會立即返回,所以會先輸出3,而異步會創(chuàng)建一個新的線程來執(zhí)行block塊,所以2最后輸出。但是2和3的順序不一定。
示例3:
輸出結(jié)果:
示例3也不會造成死鎖,因為dispatch_sync不會立即返回,而是先阻塞主線程,再將任務(wù)2加入到一個全局隊列的一個線程上去執(zhí)行,執(zhí)行完之后返回到主隊列,此時主線程不在阻塞,再繼續(xù)執(zhí)行任務(wù)3。
示例4:
輸出結(jié)果:
因為dispatch_async不會等待,所以順序是1-4-2-3-5或1-2-4-3-5,其中任務(wù)1和4是在主線程執(zhí)行的,而2是在全局隊列上被調(diào)用的,執(zhí)行完2之后,會阻塞當(dāng)前的線程(全局隊列上的),緊接著會回到主隊列上的主線程上執(zhí)行任務(wù)3,任務(wù)3執(zhí)行完之后,會繼續(xù)執(zhí)行5,此時全局隊列上的線程也不堵塞了。
注意:線程同步阻塞后不一定能造成死鎖,還要看看還有沒有其他線程去執(zhí)行那個block,如果能有,就能解鎖阻塞的線程,繼續(xù)執(zhí)行任務(wù)。如果沒有,那就是死鎖了。
示例5:
輸出結(jié)果:
最終結(jié)果還是會導(dǎo)致死鎖,因為dispatch_queue_create創(chuàng)建隊列的時候傳入NULL默認(rèn)是串行隊列,所以執(zhí)行任務(wù)2之后,會阻塞掉當(dāng)前線程,直到任務(wù)3的block執(zhí)行完成,又因為當(dāng)前線程被阻塞掉了,block也無法執(zhí)行,導(dǎo)致相互等待造成死鎖
示例6:
輸出結(jié)果:=5
因為self.num++操作是異步的,不一定能立馬返回結(jié)果,所以在進(jìn)入下次while循環(huán)的時候,self.num(主線程)可能還是0,所以循環(huán)肯定至少5次,最理想的情況下,5次全部都返回結(jié)果,而NSLog是會等待異步結(jié)果返回才會打印,所以輸出結(jié)果=5
示例7:
輸出結(jié)果為:1000
因為總共循環(huán)1000次,并不是每次結(jié)果都有返回,所以最終打印的self.num肯定小于1000
參考鏈接
大家都知道,在開發(fā)過程中應(yīng)該盡可能減少用戶等待時間,讓程序盡可能快的完成運(yùn)算。可是無論是哪種語言開發(fā)的程序最終往往轉(zhuǎn)換成匯編語言進(jìn)而解釋成機(jī)器碼來執(zhí)行。但是機(jī)器碼是按順序執(zhí)行的,一個復(fù)雜的多步操作只能一步步按順序逐個執(zhí)行。改變這種狀況可以從兩個角度出發(fā):對于單核處理器,可以將多個步驟放到不同的線程,這樣一來用戶完成UI操作后其他后續(xù)任務(wù)在其他線程中,當(dāng)CPU空閑時會繼續(xù)執(zhí)行,而此時對于用戶而言可以繼續(xù)進(jìn)行其他操作;對于多核處理器,如果用戶在UI線程中完成某個操作之后,其他后續(xù)操作在別的線程中繼續(xù)執(zhí)行,用戶同樣可以繼續(xù)進(jìn)行其他UI操作,與此同時前一個操作的后續(xù)任務(wù)可以分散到多個空閑CPU中繼續(xù)執(zhí)行(當(dāng)然具體調(diào)度順序要根據(jù)程序設(shè)計而定),及解決了線程阻塞又提高了運(yùn)行效率。蘋果從iPad2 開始使用雙核A5處理器(iPhone中從iPhone 4S開始使用),A7中還加入了協(xié)處理器,如何充分發(fā)揮這些處理器的性能確實值得思考。今天將重點(diǎn)分析iOS多線程開發(fā):
多線程
簡介
iOS多線程
NSThread
解決線程阻塞問題
多線程并發(fā)
線程狀態(tài)
擴(kuò)展-NSObject分類擴(kuò)展
NSOperation
NSInvocationOperation
NSBlockOperation
線程執(zhí)行順序
GCD
串行隊列
并發(fā)隊列
其他任務(wù)執(zhí)行方法
線程同步
NSLock同步鎖
@synchronized代碼塊
擴(kuò)展--使用GCD解決資源搶占問題
擴(kuò)展--控制線程通信
總結(jié)
目 錄
多線程
簡介
當(dāng)用戶播放音頻、下載資源、進(jìn)行圖像處理時往往希望做這些事情的時候其他操作不會被中斷或者希望這些操作過程中更加順暢。在單線程中一個線程只能做一件事情,一件事情處理不完另一件事就不能開始,這樣勢必影響用戶體驗。早在單核處理器時期就有多線程,這個時候多線程更多的用于解決線程阻塞造成的用戶等待(通常是操作完UI后用戶不再干涉,其他線程在等待隊列中,CPU一旦空閑就繼續(xù)執(zhí)行,不影響用戶其他UI操作),其處理能力并沒有明顯的變化。如今無論是移動操作系統(tǒng)還是PC、服務(wù)器都是多核處理器,于是“并行運(yùn)算”就更多的被提及。一件事情我們可以分成多個步驟,在沒有順序要求的情況下使用多線程既能解決線程阻塞又能充分利用多核處理器運(yùn)行能力。
下圖反映了一個包含8個操作的任務(wù)在一個有兩核心的CPU中創(chuàng)建四個線程運(yùn)行的情況。假設(shè)每個核心有兩個線程,那么每個CPU中兩個線程會交替執(zhí)行,兩個CPU之間的操作會并行運(yùn)算。單就一個CPU而言兩個線程可以解決線程阻塞造成的不流暢問題,其本身運(yùn)行效率并沒有提高,多CPU的并行運(yùn)算才真正解決了運(yùn)行效率問題,這也正是并發(fā)和并行的區(qū)別。當(dāng)然,不管是多核還是單核開發(fā)人員不用過多的擔(dān)心,因為任務(wù)具體分配給幾個CPU運(yùn)算是由系統(tǒng)調(diào)度的,開發(fā)人員不用過多關(guān)心系統(tǒng)有幾個CPU。開發(fā)人員需要關(guān)心的是線程之間的依賴關(guān)系,因為有些操作必須在某個操作完成完才能執(zhí)行,如果不能保證這個順序勢必會造成程序問題。
iOS多線程
在iOS中每個進(jìn)程啟動后都會建立一個主線程(UI線程),這個線程是其他線程的父線程。由于在iOS中除了主線程,其他子線程是獨(dú)立于Cocoa Touch的,所以只有主線程可以更新UI界面(新版iOS中,使用其他線程更新UI可能也能成功,但是不推薦)。iOS中多線程使用并不復(fù)雜,關(guān)鍵是如何控制好各個線程的執(zhí)行順序、處理好資源競爭問題。常用的多線程開發(fā)有三種方式:
1.NSThread
2.NSOperation
3.GCD
三種方式是隨著iOS的發(fā)展逐漸引入的,所以相比而言后者比前者更加簡單易用,并且GCD也是目前蘋果官方比較推薦的方式(它充分利用了多核處理器的運(yùn)算性能)。做過.Net開發(fā)的朋友不難發(fā)現(xiàn)其實這三種開發(fā)方式 剛好對應(yīng).Net中的多線程、線程池和異步調(diào)用,因此在文章中也會對比講解。
NSThread
NSThread是輕量級的多線程開發(fā),使用起來也并不復(fù)雜,但是使用NSThread需要自己管理線程生命周期。可以使用對象方法+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument直接將操作添加到線程中并啟動,也可以使用對象方法- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument 創(chuàng)建一個線程對象,然后調(diào)用start方法啟動線程。
解決線程阻塞問題
在資源下載過程中,由于網(wǎng)絡(luò)原因有時候很難保證下載時間,如果不使用多線程可能用戶完成一個下載操作需要長時間的等待,這個過程中無法進(jìn)行其他操作。下面演示一個采用多線程下載圖片的過程,在這個示例中點(diǎn)擊按鈕會啟動一個線程去下載圖片,下載完成后使用UIImageView將圖片顯示到界面中。可以看到用戶點(diǎn)擊完下載按鈕后,不管圖片是否下載完成都可以繼續(xù)操作界面,不會造成阻塞。
//
// NSThread實現(xiàn)多線程
// MultiThread
//
// Created by Kenshin Cui on 14-3-22.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCMainViewController.h"
@interface KCMainViewController (){
UIImageView *_imageView;
}
@end
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self layoutUI];
}
#pragma mark 界面布局
-(void)layoutUI{
_imageView =[[UIImageView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
_imageView.contentMode=UIViewContentModeScaleAspectFit;
[self.view addSubview:_imageView];
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame=CGRectMake(50, 500, 220, 25);
[button setTitle:@"加載圖片" forState:UIControlStateNormal];
//添加方法
[button addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
#pragma mark 將圖片顯示到界面
-(void)updateImage:(NSData *)imageData{
UIImage *image=[UIImage imageWithData:imageData];
_imageView.image=image;
}
#pragma mark 請求圖片數(shù)據(jù)
-(NSData *)requestData{
//對于多線程操作建議把線程操作放到@autoreleasepool中
@autoreleasepool {
NSURL *url=[NSURL URLWithString:@""];
NSData *data=[NSData dataWithContentsOfURL:url];
return data;
}
}
#pragma mark 加載圖片
-(void)loadImage{
//請求數(shù)據(jù)
NSData *data= [self requestData];
/*將數(shù)據(jù)顯示到UI控件,注意只能在主線程中更新UI,
另外performSelectorOnMainThread方法是NSObject的分類方法,每個NSObject對象都有此方法,
它調(diào)用的selector方法是當(dāng)前調(diào)用控件的方法,例如使用UIImageView調(diào)用的時候selector就是UIImageView的方法
Object:代表調(diào)用方法的參數(shù),不過只能傳遞一個參數(shù)(如果有多個參數(shù)請使用對象進(jìn)行封裝)
waitUntilDone:是否線程任務(wù)完成執(zhí)行
*/
[self performSelectorOnMainThread:@selector(updateImage:) withObject:data waitUntilDone:YES];
}
#pragma mark 多線程下載圖片
-(void)loadImageWithMultiThread{
//方法1:使用對象方法
//創(chuàng)建一個線程,第一個參數(shù)是請求的操作,第二個參數(shù)是操作方法的參數(shù)
// NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
// //啟動一個線程,注意啟動一個線程并非就一定立即執(zhí)行,而是處于就緒狀態(tài),當(dāng)系統(tǒng)調(diào)度時才真正執(zhí)行
// [thread start];
//方法2:使用類方法
[NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];
}
@end
運(yùn)行效果:
程序比較簡單,但是需要注意執(zhí)行步驟:當(dāng)點(diǎn)擊了“加載圖片”按鈕后啟動一個新的線程,這個線程在演示中大概用了5s左右,在這5s內(nèi)UI線程是不會阻塞的,用戶可以進(jìn)行其他操作,大約5s之后圖片下載完成,此時調(diào)用UI線程將圖片顯示到界面中(這個過程瞬間完成)。另外前面也提到過,更新UI的時候使用UI線程,這里調(diào)用了NSObject的分類擴(kuò)展方法,調(diào)用UI線程完成更新。
多個線程并發(fā)
上面這個演示并沒有演示多個子線程操作之間的關(guān)系,現(xiàn)在不妨在界面中多加載幾張圖片,每個圖片都來自遠(yuǎn)程請求。
大家應(yīng)該注意到不管是使用+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument、- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument 方法還是使用- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait方法都只能傳一個參數(shù),由于更新圖片需要傳遞UIImageView的索引和圖片數(shù)據(jù),因此這里不妨定義一個類保存圖片索引和圖片數(shù)據(jù)以供后面使用。
KCImageData.h
//
// KCImageData.h
// MultiThread
//
// Created by Kenshin Cui on 14-3-22.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import Foundation/Foundation.h
@interface KCImageData : NSObject
#pragma mark 索引
@property (nonatomic,assign) int index;
#pragma mark 圖片數(shù)據(jù)
@property (nonatomic,strong) NSData *data;
@end
接下來將創(chuàng)建多個UIImageView并創(chuàng)建多個線程用于往UIImageView中填充圖片。
KCMainViewController.m
//
// NSThread實現(xiàn)多線程
// MultiThread
//
// Created by Kenshin Cui on 14-3-22.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCMainViewController.h"
#import "KCImageData.h"
#define ROW_COUNT 5
#define COLUMN_COUNT 3
#define ROW_HEIGHT 100
#define ROW_WIDTH ROW_HEIGHT
#define CELL_SPACING 10
@interface KCMainViewController (){
NSMutableArray *_imageViews;
}
@end
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self layoutUI];
}
#pragma mark 界面布局
-(void)layoutUI{
//創(chuàng)建多個圖片控件用于顯示圖片
_imageViews=[NSMutableArray array];
for (int r=0; rROW_COUNT; r++) {
for (int c=0; cCOLUMN_COUNT; c++) {
UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(c*ROW_WIDTH+(c*CELL_SPACING), r*ROW_HEIGHT+(r*CELL_SPACING ), ROW_WIDTH, ROW_HEIGHT)];
imageView.contentMode=UIViewContentModeScaleAspectFit;
// imageView.backgroundColor=[UIColor redColor];
[self.view addSubview:imageView];
[_imageViews addObject:imageView];
}
}
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame=CGRectMake(50, 500, 220, 25);
[button setTitle:@"加載圖片" forState:UIControlStateNormal];
//添加方法
[button addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
#pragma mark 將圖片顯示到界面
-(void)updateImage:(KCImageData *)imageData{
UIImage *image=[UIImage imageWithData:imageData.data];
UIImageView *imageView= _imageViews[imageData.index];
imageView.image=image;
}
#pragma mark 請求圖片數(shù)據(jù)
-(NSData *)requestData:(int )index{
//對于多線程操作建議把線程操作放到@autoreleasepool中
@autoreleasepool {
NSURL *url=[NSURL URLWithString:@""];
NSData *data=[NSData dataWithContentsOfURL:url];
return data;
}
}
#pragma mark 加載圖片
-(void)loadImage:(NSNumber *)index{
// NSLog(@"%i",i);
//currentThread方法可以取得當(dāng)前操作線程
NSLog(@"current thread:%@",[NSThread currentThread]);
int i=[index integerValue];
// NSLog(@"%i",i);//未必按順序輸出
NSData *data= [self requestData:i];
KCImageData *imageData=[[KCImageData alloc]init];
imageData.index=i;
imageData.data=data;
[self performSelectorOnMainThread:@selector(updateImage:) withObject:imageData waitUntilDone:YES];
}
#pragma mark 多線程下載圖片
-(void)loadImageWithMultiThread{
//創(chuàng)建多個線程用于填充圖片
for (int i=0; iROW_COUNT*COLUMN_COUNT; ++i) {
// [NSThread detachNewThreadSelector:@selector(loadImage:) toTarget:self withObject:[NSNumber numberWithInt:i]];
NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(loadImage:) object:[NSNumber numberWithInt:i]];
thread.name=[NSString stringWithFormat:@"myThread%i",i];//設(shè)置線程名稱
[thread start];
}
}
@end
線程的不安全是由于多線程訪問和修改共享資源而引起的不可預(yù)測的結(jié)果。
ios多線程開發(fā)中為保證線程的安全常用到的幾種鎖: NSLock 、 dispatch_semaphore 、 NSCondition 、 NSRecursiveLock 、 @synchronized 。
WEAKSELF typeof(self) __weak weakSelf = self;
NSLock 是OC層封裝底層線程操作來實現(xiàn)的一種鎖,繼承NSLocking協(xié)議。不能迭代加鎖,如果發(fā)生兩次lock,而未unlock過,則會產(chǎn)生死鎖問題。
以車站購票為例,多個窗口同時售票(同步),每個窗口有人循環(huán)購票:
原子操作
原子操作是指不可打斷的操作,也就是說線程在執(zhí)行操作的過程中,不會被操作系統(tǒng)掛起,而是一定會執(zhí)行完,
變量屬性Property中的原子定義
一般我們定義一個變量@property (nonatomic ,strong)NSLock *lock;nonatomic:非原子性,不會為setter方法加鎖,適合內(nèi)存小的移動設(shè)備;atomic:原子性,默認(rèn)為setter方法加鎖(默認(rèn)就是atomic),線程安全。
PS: 在iOS開發(fā)過程中,一般都將屬性聲明為nonatomic,盡量避免多線程搶奪同一資源,盡量將加鎖等資源搶奪業(yè)務(wù)交給服務(wù)器。
NSCondition常用于生產(chǎn)者-消費(fèi)者模式,它繼承了NSLocking協(xié)議,同樣有l(wèi)ock和unlock方法。條件變量有點(diǎn)像信號量,提供了線程阻塞和信號機(jī)制,因此可以用來阻塞某個線程,并等待數(shù)據(jù)就緒再喚醒程序。
信號量主要有3個函數(shù),分別是:
注意: 正常的使用順序是先降低然后提高,這兩個函數(shù)通常都是成對出現(xiàn)。
本文主要參考了這篇文章(
),并對其中所能理解的部分進(jìn)行一一驗證,以前沒怎么寫過類似的,如果有什么做的不好的地方還請大家多多見諒!
分享題目:ios多線程開發(fā),ios開發(fā)多線程的使用
分享URL:http://www.yijiale78.com/article0/hocooo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、軟件開發(fā)、品牌網(wǎng)站制作、電子商務(wù)、搜索引擎優(yōu)化、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)