同步任務
和線程同步
是兩個概念溯捆。不要搞混了。一定要區(qū)分當前線程
和所在線程
的關系勾缭。
同步任務
:串行執(zhí)行任務,會把你的同步代碼一行一行的執(zhí)行下去目养,即使是在block里面俩由,也會等待任務完成,會阻塞當前線程癌蚁。
異步任務
:并行執(zhí)行的任務幻梯,代碼會放在另外一塊區(qū)域去執(zhí)行兜畸,不會會阻塞當前線程,不會等待執(zhí)行完畢返回結果碘梢。
異步線程
:并行執(zhí)行的任務的線程咬摇。
線程同步
:是指多個線程同時訪問一個資源時可能存在競爭問題提供的解決方案
,使多個線程可以對同一個資源進行操作,比如線程A為數(shù)組M添加了一個數(shù)據(jù)煞躬,線程B可以接收到添加數(shù)據(jù)后的數(shù)組M肛鹏。線程同步就是線程之間相互的通信。
常見比如多個線程內操作了同一個變量恩沛,這個時候一定要考慮線程安全和同步在扰。
- (void)removeLastIamgeName{//假如每個進來的都是不同的線程
//self.imageNames是NSMutableArray
if (self.imageNames.count>0) {
//比如當前count為1,那么第一個線程和第二個線程都可以進入判斷內部雷客,第一個線程刪除了數(shù)組里面最后一個數(shù)據(jù)健田,第二個線程去刪除的時候因為已經沒有數(shù)據(jù)了,count=0佛纫,這個時候取調用removeObjectAtIndex:0機會crash妓局,數(shù)組越界了
[self.imageNames removeObjectAtIndex:self.imageNames.count-1];
}
}
同步異步任務
這里有個概念容易混攪:
使用GCD創(chuàng)建一個并行隊列,如果向并行隊列添加同步任務呈宇,它并不是串行執(zhí)行的好爬。任務對于當前線程
是同步串行執(zhí)行的,對于隊列來說是并行執(zhí)行的甥啄,只是隊列里面可能每次都只有一個任務存炮,所以看起來是串行的。
GCD的隊列定義了隊列里面的任務是否支持并行蜈漓,并沒有定義任務在當前線程是同步還是異步穆桂。
dispatch_queue_t globalQueue = dispatch_queue_create([@"com.yasin.dispatchqueue" cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);;
for (int i=0; i<10; i++) {
dispatch_sync(globalQueue, ^(){
NSLog(@"%d",i);
/**
* i從0到9輸出,因為當前線程是串行的融虽,會等待同步任務執(zhí)行完畢
如果在for循環(huán)內部再起一個異步線程享完,在異步線程內執(zhí)行dispatch_sync(globalQueue, ^(),輸出就是亂序的
*/
});
}
這里會一個接著一個執(zhí)行同步線程的任務有额,并不會出現(xiàn)幾個線程同時執(zhí)行的現(xiàn)象般又。當前線程規(guī)定了要同步一個一個執(zhí)行線程任務怎么可能會并行執(zhí)行多個任務。這個代碼書寫邏輯就不對巍佑。
--小結-- 其實只要不做傻事就不會出問題茴迁,要一個一個執(zhí)行的任務就放在串行隊列里面,需要異步就異步萤衰,需要同步就同步(異步不卡當前線程堕义,同步卡當前線程);如果想要并行執(zhí)行多個任務脆栋,就放在并行隊列里面倦卖,開異步線程去做洒擦。
線程同步的方法
原子操作
我們在聲明一個變量的時候一般會使用nonatomic
,這個就是非原子操作糖耸;原子操作是atomic
秘遏。
簡單的加減使用原子操作具有更高的性能優(yōu)勢。注意是加減嘉竟,不是增刪0钗!!
也就是說僅僅對于getter,setter是線程安全的舍扰,兩個線程都去對變量賦值是安全的倦蚪。對于比如NSMutableArray類型的增刪操作不是線程安全的線程鎖
鎖可以保護臨界區(qū),代碼在臨界區(qū)同一時間只會被一個線程執(zhí)行边苹。有互斥鎖陵且、遞歸鎖、讀寫鎖个束、分布鎖慕购、自旋鎖、雙重檢查鎖等等茬底。
后續(xù)會重點介紹這部分條件沪悲、信號量
有個BOOL類型的變量,當線程A進入臨界區(qū)時把BOOL值置為NO阱表,如果線程B準備進入臨界區(qū)時發(fā)現(xiàn)BOOL值為NO就掛起等待殿如,當線程A出臨界區(qū)時把BOOL置為YES,線程B會被喚醒并繼續(xù)執(zhí)行最爬。
條件就是使用信號量在線程之間相互發(fā)生信號涉馁。
條件通常被使用來說明資源可用性,或用來確保任務以特定的順序執(zhí)行爱致。使用Selector
selector方法允許你的線程以異步的方式來傳遞消息烤送,以確保它們在同一個線程上面執(zhí)行是同步的。
比如NSObject
中的方法
performSelector:withObject:afterDelay:
performSelectorInBackground:withObject:
performSelector:onThread:withObject:waitUntilDone:
代碼:
[self performSelector:@selector(test:) withObject:nil afterDelay:1];
[self performSelectorInBackground:@selector(test:) withObject:nil];
//等效于[NSThread detachNewThreadSelector:@selector(test:) toTarget:self withObject:nil];
代碼2:
-(void)viewDidLoad
{
[super viewDidLoad];
[self threadInfo:@"UI"];
_isNewThreadAborted = NO;
_thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread:) object:nil];
//開始線程
[_thread start];
//在另一個線程中的Run Loop中執(zhí)行Selector
[self performSelector:@selector(test:) onThread:_thread withObject:nil waitUntilDone:NO];
}
//在新線程中創(chuàng)建并開始一個NSRunLoop
-(void)newThread:(id)obj
{
@autoreleasepool
{
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
while (!_isNewThreadAborted)
{
[currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"線程停止");
}
}
//Selector執(zhí)行
-(void)test:(id)obj
{
[self threadInfo:@"test"];
_isNewThreadAborted = YES;
}
-(void)threadInfo:(NSString*)category
{
NSLog(@"%@ - %@", category, [NSThread currentThread]);
}
- 內存屏障和 Volatile 變量
OSMemoryBarrier函數(shù)蒜鸡,設置內存屏蔽
volatile變量
因為內存屏障和volatile變量降低了編譯器可執(zhí)行的優(yōu)化胯努,因此你應該謹慎使用它們,只在有需要的地方時候逢防,以確保正確性。
這部分涉及編譯器蒲讯,現(xiàn)在還不是很理解忘朝,以后再補充
并行并發(fā)
并發(fā)編程、并發(fā)程序判帮,和并行計算機局嘁。
并發(fā)性與軟件結構有關溉箕,而并行性與硬件有關。
也就是說悦昵,并發(fā)就是多線程編程肴茄,并行就是多核處理器。
天下武功出少林
這里推薦一個特別好的文章iOS多線程編程指南(四)線程同步
后續(xù)我會著重研究線程鎖這一塊