參考:
補(bǔ)充隊(duì)列伞访、任務(wù)、同步異步的理解
- 任務(wù):放在隊(duì)列中的一段代碼塊轰驳,同一個(gè)任務(wù)中的代碼是相繼執(zhí)行的厚掷。
- 隊(duì)列:相當(dāng)于購(gòu)物的顧客;串行隊(duì)列表示需要排隊(duì)级解,并行隊(duì)列是不需要排隊(duì)的冒黑。
- 同步異步函數(shù):相當(dāng)于服務(wù)窗口,一個(gè)窗口一個(gè)線程勤哗。
- 同步是表示就在當(dāng)前窗口抡爹,不給你在開(kāi)個(gè)窗口;
- 異步表示開(kāi)新窗口芒划,開(kāi)幾個(gè)根據(jù)任務(wù)數(shù)了冬竟,如果沒(méi)有任務(wù)欧穴,就不會(huì)開(kāi)線程了。因?yàn)樽泳€程是沒(méi)有開(kāi)啟runLoop的泵殴,任務(wù)執(zhí)行完了涮帘,自動(dòng)會(huì)關(guān)閉的
主隊(duì)列是串行隊(duì)列,全局隊(duì)列是并行對(duì)列
下面代碼可以很好的理解任務(wù)隊(duì)列笑诅、同步異步的理解
dispatch_async(dispatch_queue_create("d", DISPATCH_QUEUE_CONCURRENT), ^{
NSLog(@"www");
//隊(duì)列是排隊(duì)焚辅,同步異步是是否開(kāi)窗口。任務(wù)添加到隊(duì)列苟鸯。異步等任務(wù)執(zhí)行完才會(huì)返回結(jié)果同蜻,才算完成
sleep(1);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"fff");
});
NSLog(@"ff");
});
sleep(1);
NSLog(@"fdffdfd");
打印:www;fdffdfd;fff;ff
一早处、dispatch_timer 定時(shí)器
//1.創(chuàng)建隊(duì)列湾蔓,并行隊(duì)列還是主隊(duì)列看情況
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//創(chuàng)建定時(shí)器
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//設(shè)置定時(shí)器的兩種方式:
1. 只設(shè)置時(shí)間間隔
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0);//1
2. 設(shè)置時(shí)間間隔為1s,設(shè)置開(kāi)始時(shí)間為0s后
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW,0), 1 * NSEC_PER_SEC, 0);/
dispatch_source_set_event_handler(_timer, ^{
NSLog(@"fdf");
});
dispatch_resume(_timer);
注:NSEC_PRE_SEC 表示每一秒一納秒
二砌梆、死鎖和阻塞線程
1.首先理解幾個(gè)概念:同步和異步默责,串行和并發(fā):
-
同步和異步
:同步表示阻塞當(dāng)前線程,異步表示不阻塞咸包。 -
串行和并發(fā)
:是隊(duì)列桃序,用來(lái)添加容納任務(wù)。串行隊(duì)列烂瘫,任務(wù)是有順序的媒熊,先進(jìn)先出,任務(wù)依次結(jié)束坟比。并發(fā)芦鳍,也遵循先進(jìn)先出,但任務(wù)結(jié)束順序呢不定
2.理解隊(duì)列是如何執(zhí)行的葛账,什么情況會(huì)死鎖柠衅,什么情況會(huì)阻塞線程,舉例說(shuō)明:
注:1. 阻塞線程:同步阻塞籍琳。同步函數(shù)的block任務(wù)必須執(zhí)行完之后才會(huì)返回值 2.添加任務(wù):是添加到指定隊(duì)列的隊(duì)尾 3.死鎖:代碼停了下來(lái)菲宴,不會(huì)往下執(zhí)行 3.開(kāi)線程:同步函數(shù)是不會(huì)開(kāi)線程的,異步并且非主隊(duì)列就會(huì)開(kāi)線程 4.并發(fā)隊(duì)列的任務(wù)不會(huì)相互等待(原因不知:可能是并發(fā)執(zhí)行趋急,不許排隊(duì)吧)
main{
dispatch_sync(dispatch_get_main_queue(), ^(void){
NSLog(@"這里死鎖了");
});
}
//會(huì)死鎖喝峦。首先同步線程,阻塞當(dāng)前線程(主線程)宣谈,block任務(wù)添加到主隊(duì)列的結(jié)尾愈犹,所以block任務(wù)會(huì)等待同步函數(shù)執(zhí)行完再執(zhí)行block键科,但同步函數(shù)必須在block執(zhí)行完之后才會(huì)有返回值闻丑,block任務(wù)又在等同步函數(shù)以及同步函數(shù)后的任務(wù)執(zhí)行完后才會(huì)執(zhí)行漩怎。block和其他主隊(duì)列中的任務(wù)形成死鎖。
main{
dispatch_queue_t queue = dispatch_queue_create("d", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^(void){
NSLog(@"這就不死鎖了");
});
}
//不會(huì)死鎖嗦嗡,會(huì)阻塞線程勋锤。首先沒(méi)有開(kāi)線程,同步就會(huì)阻塞線程侥祭,因?yàn)橐萣lock執(zhí)行完,才會(huì)往下執(zhí)行叁执。不會(huì)死鎖是因?yàn)槿蝿?wù)添加到了另一個(gè)非主隊(duì)列中,主隊(duì)列只需等待block任務(wù)完成就可繼續(xù)下面的任務(wù)矮冬,block不需等主隊(duì)列任務(wù)完成谈宛。
main{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_sync(queue, ^{
dispatch_sync(queue, ^(void){
NSLog(@"這就不死鎖了");
});
NSLog(@"ddd");
});
}
//不會(huì)死鎖,會(huì)阻塞線程胎署。并發(fā)任務(wù)不用排隊(duì)吆录,所以不會(huì)死鎖。
三琼牧、group
步驟一
:先通過(guò)異步函數(shù)將任務(wù)都添加到并發(fā)隊(duì)列中dispatch_group_async(group, queue, ^{}
步驟二
:執(zhí)行結(jié)束函數(shù)dispatch_group_notify(group, queue, ^{}
//例:異步下載兩張圖片恢筝,下載完成后合成一張圖片
- (void)group
{
UIImageView *imageView = [[UIImageView alloc] init];
[self.view addSubview:imageView];
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("cn.gcd-group.www", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
NSLog(@"正在下載第一張圖片");
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://images2015.cnblogs.com/blog/471463/201509/471463-20150912213125372-589808688.png"]];
NSLog(@"第一張圖片下載完畢");
self.imageOne = [UIImage imageWithData:data];
});
dispatch_group_async(group, queue, ^{
NSLog(@"正在下載第二張圖片");
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://images2015.cnblogs.com/blog/471463/201509/471463-20150912212457684-585830854.png"]];
NSLog(@"第二張圖片下載完畢");
self.imageTwo = [UIImage imageWithData:data];
});
dispatch_group_notify(group, queue, ^{
UIGraphicsBeginImageContext(CGSizeMake(300, 400));
[self.imageOne drawInRect:CGRectMake(0, 0, 150, 400)];
[self.imageTwo drawInRect:CGRectMake(150, 0, 150, 400)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^{
UIImageView *imageView = [[UIImageView alloc] initWithImage:newImage];
[self.view addSubview:imageView];
self.textLabel.text = @"圖片合并完畢";
});
});
}
四 dispatch_semaphore_t
dispatch_semaphore
信號(hào)量基于計(jì)數(shù)器的一種多線程同步機(jī)制。在多個(gè)線程訪問(wèn)共有資源時(shí)候巨坊,會(huì)因?yàn)槎嗑€程的特性而引發(fā)數(shù)據(jù)出錯(cuò)的問(wèn)題撬槽。
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray *array = [NSMutableArrayarray];
for (int index = 0; index < 100000; index++) {
dispatch_async(queue, ^(){
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//
NSLog(@"addd :%d", index);
[array addObject:[NSNumber numberWithInt:index]];
dispatch_semaphore_signal(semaphore);
});
}
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
如果semaphore
計(jì)數(shù)大于等于1.計(jì)數(shù)-1,返回趾撵,程序繼續(xù)運(yùn)行侄柔。如果計(jì)數(shù)為0,則等待占调。這里設(shè)置的等待時(shí)間是一直等待勋拟。dispatch_semaphore_signal(semaphore);
計(jì)數(shù)+1.在這兩句代碼中間的執(zhí)行代碼,每次只會(huì)允許一個(gè)線程進(jìn)入妈候,這樣就有效的保證了在多線程環(huán)境下敢靡,只能有一個(gè)線程進(jìn)入。