1:現(xiàn)有的幾種多線程
一般移動(dòng)平臺(tái)上系統(tǒng)都會(huì)有一個(gè)專門的檢查機(jī)制,,看程序有沒有很長時(shí)間被阻塞住,沒有回來檢查主消息隊(duì)列,。發(fā)現(xiàn)這種情況一般都是把程 序作為“無響應(yīng)”干掉,。iOS一般情況下是10秒為上限。10秒內(nèi)程序沒有回到主消息循環(huán)就被干掉,。在前臺(tái)后臺(tái)切換時(shí)更嚴(yán)格,,大概是5秒左右。 注釋1 2:簡(jiǎn)單的Demo因?yàn)镚CD 是應(yīng)用最廣的 而且也是蘋果現(xiàn)在極力鼓動(dòng)開發(fā)者應(yīng)用的 所以NSThread NSOperation 只做簡(jiǎn)單應(yīng)用 1:NSThread1.1 NSThread 有兩種直接創(chuàng)建方式:第一個(gè)是實(shí)例方法--直接創(chuàng)建線程并且開始運(yùn)行線程
第二個(gè)是類方法--先創(chuàng)建線程對(duì)象,,然后再運(yùn)行線程操作,,在運(yùn)行線程操作前可以設(shè)置線程的優(yōu)先級(jí)等線程信息
selector
:線程執(zhí)行的方法,,這個(gè)selector只能有一個(gè)參數(shù),而且不能有返回值,。
1.2線程間通信a 在應(yīng)用程序主線程中做事情: performSelectorOnMainThread:withObject:waitUntilDone: performSelectorOnMainThread:withObject:waitUntilDone:modes: b 在指定線程中做事情: performSelector:onThread:withObject:waitUntilDone: performSelector:onThread:withObject:waitUntilDone:modes: c 在當(dāng)前線程中做事情: performSelector:withObject:afterDelay: performSelector:withObject:afterDelay:inModes: d 取消發(fā)送給當(dāng)前線程的某個(gè)消息 cancelPreviousPerformRequestsWithTarget: cancelPreviousPerformRequestsWithTarget:selector:object: 2:NSOperation首先是建立NSOperationQueue和NSOperations。NSOperationQueue會(huì)建立一個(gè)線程管理器,,每個(gè)加入到線程operation會(huì)有序的執(zhí)行,。 NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doWork:) object:someObject];
[queue addObject:operation];
[operation release];
使用NSOperationQueue的過程:
NSInvocationOperation,NSInvocationOperation是NSOperation的子類,,允許運(yùn)行在operation中的targer和selector 3:多線程互斥同步問題在iOS中有幾種方法來解決多線程訪問同一個(gè)內(nèi)存地址的互斥同步問題:
@synchronized(self) { // 這段代碼對(duì)其他 @synchronized(self) 都是互斥的 // self 指向同一個(gè)對(duì)象 }
NSLock對(duì)象實(shí)現(xiàn)了NSLocking protocol,,包含幾個(gè)方法: lock,加鎖 unlock,,解鎖 tryLock,,嘗試加鎖,如果失敗了,,并不會(huì)阻塞線程,,只是立即返回NO lockBeforeDate:,在指定的date之前暫時(shí)阻塞線程(如果沒有獲取鎖的話),,如果到期還沒有獲取鎖,,則線程被喚醒,函數(shù)立即返回NO 比如 : NSLock *theLock = [[NSLock alloc] init];
if ([theLock lock]) { //do something here [theLock unlock]; }
NSRecursiveLock,多次調(diào)用不會(huì)阻塞已獲取該鎖的線程,。
NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
void MyRecursiveFunction(int value) {
[theLock lock];
if (value != 0) {
–value;
MyRecursiveFunction(value);
}
[theLock unlock];
}
MyRecursiveFunction(5);
NSConditionLock,,條件鎖,,可以設(shè)置條件
//公共部分
id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
//線程一,生產(chǎn)者
while(true) {
[condLock lockWhenCondition:NO_DATA];
//生產(chǎn)數(shù)據(jù)
[condLock unlockWithCondition:HAS_DATA];
}
//線程二,,消費(fèi)者
while (true) {
[condLock lockWhenCondition:HAS_DATA
//消費(fèi)
[condLock unlockWithCondition:NO_DATA];
}
NSDistributedLock,,分布鎖,,文件方式實(shí)現(xiàn),可以跨進(jìn)程 用tryLock方法獲取鎖,。 用unlock方法釋放鎖,。 如果一個(gè)獲取鎖的進(jìn)程在釋放鎖之前掛了,,那么鎖就一直得不到釋放了,此時(shí)可以通過breakLock強(qiáng)行獲取鎖,。 本章節(jié)(多線程互斥同步問題)參考自: http://blog.sina.com.cn/s/blog_72819b170101590n.html 3:GCD多線程互斥同步問題(阻塞線程的方式去實(shí)現(xiàn)同步)1.串行隊(duì)列(1)GCD下的dispatch_queue隊(duì)列都是FIFO隊(duì)列,都會(huì)按照提交到隊(duì)列的順序執(zhí)行. 只是根據(jù)隊(duì)列的性質(zhì),分為 <1>串行隊(duì)列:用戶隊(duì)列,、主線程隊(duì)列 <2>并行隊(duì)列.
(2)同步(dispatch_sync)、異步方式(dispatch_async). 配合串行隊(duì)列和并行隊(duì)列使用.
//開始時(shí)間 NSDate *startTime = [NSDate date]; __block UIImage *image = nil; //1.先去網(wǎng)上下載圖片 dispatch_async(serilQueue, ^{ //下載圖片 }); //2.在主線程展示到界面里 dispatch_async(serilQueue, ^{ NSLog(@"%@",[NSThread currentThread]); // 在主線程展示 dispatch_async(dispatch_get_main_queue(), ^{ //顯示圖片 }); //3.清理 dispatch_release(serilQueue); [image release]; 注意: (1) __block變量分配在棧,retain下,防止被回收. (2)dispatch要手動(dòng)create和release. (3)提交到主線程隊(duì)列的時(shí)候,慎用同步dispatch_sync方法,有可能造成死鎖. 因?yàn)橹骶€程隊(duì)列是串行隊(duì)列,要等隊(duì)列里的任務(wù)一個(gè)一個(gè)執(zhí)行.所以提交一個(gè)任務(wù)到隊(duì)列,如果用同步方法就會(huì)阻塞住主線程,而主線程又要等主線程隊(duì)列里的任務(wù)都執(zhí)行完才能執(zhí)行那個(gè)剛提交的,所以主線程隊(duì)列里還有其他的任務(wù)的話,但他已經(jīng)被阻塞住了,沒法先完成隊(duì)列里的其他任務(wù),即,最后一個(gè)任務(wù)也沒機(jī)會(huì)執(zhí)行到,于是造成死鎖. (4)提交到串行隊(duì)列可以用同步方式,也可以用異步方式. 2.并行隊(duì)列采用并行隊(duì)列的時(shí)候,可以采用同步的方式把任務(wù)提交到隊(duì)列里去,即可以實(shí)現(xiàn)同步的方式 //新建一個(gè)隊(duì)列 dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//記時(shí) NSDate *startTime = [NSDate date]; //加入隊(duì)列 dispatch_async(concurrentQueue, ^{ __block UIImage *image = nil; //1.先去網(wǎng)上下載圖片 dispatch_sync(concurrentQueue, ^{ //下載圖片 }); //2.在主線程展示到界面里 dispatch_sync(dispatch_get_main_queue(), ^{ //顯示圖片 }); }); 兩個(gè)同步的任務(wù)用一個(gè)異步的包起來,提交到并行隊(duì)列里去,即可實(shí)現(xiàn)同步的方式. 3.使用分組方式group本身是將幾個(gè)有關(guān)聯(lián)的任務(wù)組合起來,然后提供給開發(fā)者一個(gè)知道這個(gè)group結(jié)束的點(diǎn). 雖然這個(gè)只有一個(gè)任務(wù),但是可以利用group的結(jié)束點(diǎn),去阻塞線程,從而來實(shí)現(xiàn)同步方式. 例如讓后臺(tái)2個(gè)線程并行執(zhí)行,,然后等2個(gè)線程都結(jié)束后,,再匯總執(zhí)行結(jié)果。這個(gè)可以用dispatch_group, dispatch_group_async 和 dispatch_group_notify來實(shí)現(xiàn),,示例如下: dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ // 并行執(zhí)行的線程一 }); dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ // 并行執(zhí)行的線程二 }); dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{ // 匯總結(jié)果 });
dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_get_global_queue(0, 0); NSDate *startTime = [NSDate date]; __block UIImage *image = nil; dispatch_group_async(group, queue, ^{ //1.先去網(wǎng)上下載圖片 }); // 2.等下載好了再在刷新主線程 dispatch_group_notify(group, queue, ^{ //在主線程展示到界面里 dispatch_async(dispatch_get_main_queue(), ^{ //顯示圖片 }); }); // 釋放掉 dispatch_release(group); dispatch_group 也要手動(dòng)創(chuàng)建和釋放. dispatch_notify()提供了一個(gè)知道group什么時(shí)候結(jié)束的點(diǎn). 當(dāng)然也可以使用dispatch_wait()去阻塞 4.信號(hào)量信號(hào)量 和 瑣 的作用差不多,可以用來實(shí)現(xiàn)同步的方式. 但是信號(hào)量通常用在 允許幾個(gè)線程同時(shí)訪問一個(gè)資源,通過信號(hào)量來控制訪問的線程個(gè)數(shù). // 信號(hào)量初始化為1 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); NSDate *startTime = [NSDate date]; __block UIImage *image = nil; //1.先去網(wǎng)上下載圖片 dispatch_async(queue, ^{ // wait操作-1 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 開始下載 // signal操作+1 dispatch_semaphore_signal(semaphore); }); // 2.等下載好了再在刷新主線程 dispatch_async(dispatch_get_main_queue(), ^{ // wait操作-1 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //顯示圖片 // signal操作+1 dispatch_semaphore_signal(semaphore); });
dispatch_wait會(huì)阻塞線程并且檢測(cè)信號(hào)量的值,直到信號(hào)量值大于0才會(huì)開始往下執(zhí)行,同時(shí)對(duì)信號(hào)量執(zhí)行-1操作.
3.后臺(tái)運(yùn)行GCD的另一個(gè)用處是可以讓程序在后臺(tái)較長久的運(yùn)行,。在沒有使用GCD時(shí),當(dāng)app被按home鍵退出后,,app僅有最多5秒鐘的時(shí)候做一些保存或清理資源的工作,。但是在使用GCD后,app最多有10分鐘的時(shí)間在后臺(tái)長久運(yùn)行,。這個(gè)時(shí)間可以用來做清理本地緩存,,發(fā)送統(tǒng)計(jì)數(shù)據(jù)等工作。 讓程序在后臺(tái)長久運(yùn)行的示例代碼如下: // AppDelegate.h文件 @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask; // AppDelegate.m文件 - (void)applicationDidEnterBackground:(UIApplication *)application { [self beingBackgroundUpdateTask]; // 在這里加上你需要長久運(yùn)行的代碼 [self endBackgroundUpdateTask]; } - (void)beingBackgroundUpdateTask { self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [self endBackgroundUpdateTask]; }]; } - (void)endBackgroundUpdateTask { [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask]; self.backgroundUpdateTask = UIBackgroundTaskInvalid; } [1] http://www.cnblogs.com/linyawen/archive/2012/07/24/2606709.html [2] http://www.cnblogs.com/Quains/archive/2013/07/10/3182823.html [3] http://blog./blog/2012/02/22/use-gcd/ 另外 本人打算十一后離職換份工作,哪位仁兄公司有意向 站內(nèi)信聯(lián)系,幫忙內(nèi)推下哈. 再打下廣告哈 我搭建的個(gè)人博客 也已經(jīng)上線了 引用的是hexo , 地址是 hufeng825.github.com ui配色再微調(diào)中,對(duì)ie10 以下支持不太好 建議用chrome Firefox 或者safrari 瀏覽 另外也已經(jīng)對(duì)移動(dòng)設(shè)備做了響應(yīng)是布局. |
|