
1. iOS中的互斥鎖
在編程中,引入對象互斥鎖的概念,來保證共享數(shù)據(jù)操作的完整性。每個對象都對應(yīng)于一個可稱為“互斥鎖”的標記,這個標記用來保證在任一時刻,只能有一個線程訪問對象。
1.1 @synchronized (self)
-?(void)lock1?{
@synchronized(self)?{
//?加鎖操作
}
}
1.2 NSLock
-?(void)lock2?{
NSLock*xwlock?=?[[NSLockalloc]?init];
XWLogBlock?logBlock?=?^?(NSArray*array)?{
[xwlock?lock];
for(idobjinarray)?{
NSLog(@"%@",obj);
}
[xwlock?unlock];
};
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
NSArray*array?=?@[@1,@2,@3];
logBlock(array);
});
}
1.3 pthread
pthread除了創(chuàng)建互斥鎖,還可以創(chuàng)建遞歸鎖、讀寫鎖、once等鎖
__block?pthread_mutex_t?mutex;
pthread_mutex_init(&mutex,NULL);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
NSLog(@"+++++?線程1?start");
pthread_mutex_lock(&mutex);
sleep(2);
pthread_mutex_unlock(&mutex);
NSLog(@"+++++?線程1?end");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
NSLog(@"-----?線程2?start");
pthread_mutex_lock(&mutex);
sleep(3);
pthread_mutex_unlock(&mutex);
NSLog(@"-----?線程2?end");
});
}
2. iOS中的遞歸鎖
同一個線程可以多次加鎖,不會造成死鎖
死鎖->
-?(void)lock5?{
NSLock?*commonLock?=?[[NSLock?alloc]?init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
staticvoid(^XWRecursiveBlock)(int);
XWRecursiveBlock?=?^(intvalue)?{
[commonLock?lock];
if(value>0)?{
NSLog(@"加鎖層數(shù):?%d",value);
sleep(1);
XWRecursiveBlock(--value);
}
NSLog(@"程序退出!");
[commonLock?unlock];
};
XWRecursiveBlock(3);
});
}
<-死鎖
2.1 NSRecursiveLock
-?(void)lock4?{
NSRecursiveLock?*recursiveLock?=?[[NSRecursiveLock?alloc]?init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
staticvoid(^XWRecursiveBlock)(int);
XWRecursiveBlock?=?^(intvalue)?{
[recursiveLock?lock];
if(value>0)?{
NSLog(@"加鎖層數(shù):?%d",value);
sleep(1);
XWRecursiveBlock(--value);
}
NSLog(@"程序退出!");
[recursiveLock?unlock];
};
XWRecursiveBlock(3);
});
}
2.2 pthread
-?(void)lock6?{
__block?pthread_mutex_t?recursiveMutex;
pthread_mutexattr_t?recursiveMutexattr;
pthread_mutexattr_init(&recursiveMutexattr);
pthread_mutexattr_settype(&recursiveMutexattr,?PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&recursiveMutex,?&recursiveMutexattr);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
staticvoid(^XWRecursiveBlock)(int);
XWRecursiveBlock?=?^(intvalue)?{
pthread_mutex_lock(&recursiveMutex);
if(value>0)?{
NSLog(@"加鎖層數(shù):?%d",value);
sleep(1);
XWRecursiveBlock(--value);
}
NSLog(@"程序退出!");
pthread_mutex_unlock(&recursiveMutex);
};
XWRecursiveBlock(3);
});
}
3. 信號量
信號量(Semaphore),有時被稱為信號燈,是在多線程環(huán)境下使用的一種設(shè)施,是可以用來保證兩個或多個關(guān)鍵代碼段不被并發(fā)調(diào)用。在進入一個關(guān)鍵代碼段之前,線程必須獲取一個信號量;一旦該關(guān)鍵代碼段完成了,那么該線程必須釋放信號量。其它想進入該關(guān)鍵代碼段的線程必須等待直到第一個線程釋放信號量
3.1 dispatch_semaphore_t
實現(xiàn) GCD 下同步
-?(void)lock7?{
//????dispatch_semaphore_create?//創(chuàng)建一個信號量?semaphore
//????dispatch_semaphore_signal?//發(fā)送一個信號?信號量+1
//????dispatch_semaphore_wait???//?等待信號?信號量-1
///?需求:?異步線程的兩個操作同步執(zhí)行
dispatch_semaphore_t?semaphone?=?dispatch_semaphore_create(0);
NSLog(@"start");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
NSLog(@"async?....?");
sleep(5);
///?線程資源?+?1
dispatch_semaphore_signal(semaphone);//信號量+1
});
///?當前線程資源數(shù)量為?0?,等待激活
dispatch_semaphore_wait(semaphone,?DISPATCH_TIME_FOREVER);
NSLog(@"end");
}
3.2 pthread
-?(void)lock8?{
__block?pthread_mutex_t?semaphore?=?PTHREAD_MUTEX_INITIALIZER;
__block?pthread_cond_t?cond?=?PTHREAD_COND_INITIALIZER;
NSLog(@"start");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
pthread_mutex_lock(&semaphore);
NSLog(@"async...");
sleep(5);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&semaphore);
});
pthread_cond_wait(&cond,?&semaphore);
NSLog(@"end");
}
4. 條件鎖
4.1 NSCondition
NSCondition 的對象實際上是作為一個鎖和線程檢查器,鎖主要是為了檢測條件時保護數(shù)據(jù)源,執(zhí)行條件引發(fā)的任務(wù)。線程檢查器主要是根據(jù)條件決定是否繼續(xù)運行線程,即線程是否被阻塞。
NSCondition同樣實現(xiàn)了NSLocking協(xié)議,所以它和NSLock一樣,也有NSLocking協(xié)議的lock和unlock方法,可以當做NSLock來使用解決線程同步問題,用法完全一樣。
-?(NSMutableArray*)removeLastImage:(NSMutableArray*)images?{
if(images.count?>0)?{
NSCondition*condition?=?[[NSConditionalloc]?init];
[condition?lock];
[images?removeLastObject];
[condition?unlock];
NSLog(@"removeLastImage?%@",images);
returnimages;
}else{
returnNULL;
}
}
同時,NSCondition提供更高級的用法。wait和signal,和條件信號量類似。
NSCondition和NSLock、@synchronized等是不同的是,NSCondition可以給每個線程分別加鎖,加鎖后不影響其他線程進入臨界區(qū)。這是非常強大。
-?(void)lock10?{
self.conditionArray?=?[NSMutableArrayarray];
self.xwCondition?=?[[NSConditionalloc]?init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
[self.xwCondition?lock];
if(self.conditionArray.count?==0)?{
NSLog(@"等待制作數(shù)組");
[self.xwCondition?wait];
}
idobj?=self.conditionArray[0];
NSLog(@"獲取對象進行操作:%@",obj);
[self.xwCondition?unlock];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
[self.xwCondition?lock];
idobj?=@"極客";
[self.conditionArray?addObject:obj];
NSLog(@"創(chuàng)建了一個對象:%@",obj);
[self.xwCondition?signal];
[self.xwCondition?unlock];
});
}
4.2 NSConditionLock
-?(void)lock11?{
NSConditionLock*conditionLock?=?[[NSConditionLockalloc]?init];
NSMutableArray*arrayM?=?[NSMutableArrayarray];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
[conditionLock?lock];
for(inti?=0;?i?<6;?i++)?{
[arrayM?addObject:@(i)];
NSLog(@"異步下載第?%d?張圖片",i);
sleep(1);
if(arrayM.count?==4)?{
[conditionLock?unlockWithCondition:4];
}
}
});
dispatch_async(dispatch_get_main_queue(),?^{
[conditionLock?lockWhenCondition:4];
NSLog(@"已經(jīng)獲取到4張圖片->主線程渲染");
[conditionLock?unlock];
});
}
4.3 pthread POSIX Conditions
-?(void)lock12?{
__block?pthread_mutex_t?mutex;
__block?pthread_cond_t?condition;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&condition,NULL);
NSMutableArray*arrayM?=?[NSMutableArrayarray];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),?^{
pthread_mutex_lock(&mutex);
for(inti?=0;?i?<6;?i++)?{
[arrayM?addObject:@(i)];
NSLog(@"異步下載第?%d?張圖片",i);
sleep(1);
if(arrayM.count?==4)?{
pthread_cond_signal(&condition);
}
}
});
dispatch_async(dispatch_get_main_queue(),?^{
pthread_cond_wait(&condition,?&mutex);
NSLog(@"已經(jīng)獲取到4張圖片->主線程渲染");
pthread_mutex_unlock(&mutex);
});
}
5. 讀寫鎖
讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。這種鎖相對于自旋鎖而言,能提高并發(fā)性,因為在多處理器系統(tǒng)中,它允許同時有多個讀者來訪問共享資源,最大可能的讀者數(shù)為實際的邏輯CPU數(shù)。寫者是排他性的,一個讀寫鎖同時只能有一個寫者或多個讀者(與CPU數(shù)相關(guān)),但不能同時既有讀者又有寫者。
5.1 dispatch_barrier_async / dispatch_barrier_sync
有一個需求,如圖:

任務(wù)1,2,3 均執(zhí)行完畢執(zhí)行任務(wù)0,然后執(zhí)行任務(wù)4,5,6.
-?(void)lock13?{
dispatch_queue_tqueue?=?dispatch_queue_create("com.qiuxuewei.brrier",?DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue,?^{
NSLog(@"任務(wù)1?--?%@",[NSThreadcurrentThread]);
});
dispatch_async(queue,?^{
NSLog(@"任務(wù)2?--?%@",[NSThreadcurrentThread]);
});
dispatch_async(queue,?^{
NSLog(@"任務(wù)3?--?%@",[NSThreadcurrentThread]);
});
dispatch_barrier_sync(queue,?^{
NSLog(@"任務(wù)0?--?%@",[NSThreadcurrentThread]);
for(inti?=0;?i?<100;?i++)?{
if(i?%30==0)?{
NSLog(@"任務(wù)0?---?log:%d?--?%@",i,[NSThreadcurrentThread]);
}
}
});
NSLog(@"dispatch_barrier_sync??down!!!");
dispatch_async(queue,?^{
NSLog(@"任務(wù)4?--?%@",[NSThreadcurrentThread]);
});
dispatch_async(queue,?^{
NSLog(@"任務(wù)5?--?%@",[NSThreadcurrentThread]);
});
dispatch_async(queue,?^{
NSLog(@"任務(wù)6?--?%@",[NSThreadcurrentThread]);
});
}
dispatch_barrier_async 和 dispatch_barrier_sync 的異同
共同點
等待它前面的執(zhí)行完才執(zhí)行自己的任務(wù)
等待自己任務(wù)執(zhí)行結(jié)束才執(zhí)行后面的任務(wù)
不同點
dispatch_barrier_async 將自己的任務(wù)插入到隊列之后會繼續(xù)將后面的操作插入到隊列,按照規(guī)則先執(zhí)行前面隊列的任務(wù),等自己隊列執(zhí)行完畢,再執(zhí)行后面隊列的任務(wù)
dispatch_barrier_sync ?將自己的任務(wù)插入到隊列之后,先等待自己的任務(wù)執(zhí)行完畢才會執(zhí)行后面操作插入到隊列,再執(zhí)行后面隊列的任務(wù)。
5.2 pthread
-?(void)lock14?{
__block?pthread_rwlock_t?rwlock;
pthread_rwlock_init(&rwlock,NULL);
__blockNSMutableArray*arrayM?=?[NSMutableArrayarray];
XWBlock?writeBlock?=?^?(NSString*str)?{
NSLog(@"開啟寫操作");
pthread_rwlock_wrlock(&rwlock);
[arrayM?addObject:str];
sleep(2);
pthread_rwlock_unlock(&rwlock);
};
XWVoidBlock?readBlock?=?^?{
NSLog(@"開啟讀操作");
pthread_rwlock_rdlock(&rwlock);
sleep(1);
NSLog(@"讀取數(shù)據(jù):%@",arrayM);
pthread_rwlock_unlock(&rwlock);
};
for(inti?=0;?i?<5;?i++)?{
dispatch_async(dispatch_get_global_queue(0,0),?^{
writeBlock([NSStringstringWithFormat:@"%d",i]);
});
}
for(inti?=0;?i?<10;?i++)?{
dispatch_async(dispatch_get_global_queue(0,0),?^{
readBlock();
});
}
}
6.自旋鎖
boollock=false;//?一開始沒有鎖上,任何線程都可以申請鎖??
do{
while(lock);//?如果?lock?為?true?就一直死循環(huán),相當于申請鎖
lock=true;//?掛上鎖,這樣別的線程就無法獲得鎖
Critical?section//?臨界區(qū)
lock=false;//?相當于釋放鎖,這樣別的線程可以進入臨界區(qū)
Reminder?section//?不需要鎖保護的代碼????????
}
6.1 OSSpinLock
YYKit作者的文章?不再安全的 OSSpinLock有說到這個自旋鎖存在優(yōu)先級反轉(zhuǎn)的問題。
6.2 os_unfair_lock
自旋鎖已經(jīng)不再安全,然后蘋果又整出來個 os_unfair_lock_t ,這個鎖解決了優(yōu)先級反轉(zhuǎn)的問題。
os_unfair_lock_tunfairLock;
unfairLock?=?&(OS_UNFAIR_LOCK_INIT);
os_unfair_lock_lock(unfairLock);
os_unfair_lock_unlock(unfairLock);
7. property - atomic / nonatomic
atomic 修飾的對象,系統(tǒng)會保證在其自動生成的 getter/setter 方法中的操作是完整的,不受其他線程的影響。例如 A 線程在執(zhí)行 getter 方法時,B線程執(zhí)行了 setter 方法,此時 A 線程依然會得到一個完整無損的對象。
atomic
默認修飾符
會保證CPU能在別的線程訪問這個屬性之前先執(zhí)行完當前操作
讀寫速度慢
線程不安全 - 如果有另一個線程 D 同時在調(diào)[name release],那可能就會crash,因為 release 不受 getter/setter 操作的限制。也就是說,這個屬性只能說是讀/寫安全的,但并不是線程安全的,因為別的線程還能進行讀寫之外的其他操作。線程安全需要開發(fā)者自己來保證。
nonatomic
不默認
速度更快
線程不安全
如果兩個線程同時訪問會出現(xiàn)不可預(yù)料的結(jié)果。
8. Once 原子操作
8.1 GCD
-?(id)lock15?{
staticidshareInstance;
staticdispatch_once_tonceToken;
dispatch_once(&onceToken,?^{
if(!shareInstance)?{
shareInstance?=?[[NSObjectalloc]?init];
}
});
returnshareInstance;
}
8.2 pthread
-?(void)lock16?{
pthread_once_tonce?=?PTHREAD_ONCE_INIT;
pthread_once(&once,?lock16Func);
}
voidlock16Func(){
staticid?shareInstance;
shareInstance?=?[[NSObject?alloc]?init];
}