1.多线程的同步,异步,串行,并行的区别和联系
同步:无论是串行还是并行,都按照主线程顺序执行;
异步:串行的时候顺序执行,并行的时候无序执行;
2.几个概念:
GitHub地址:
https://github.com/yaoqiGetHub/OCDispatchQueueDemo
异步提交的任务立刻返回,在后台队列中执行 (自己的理解:提交任务后立即返回,一些耗时的操作在后台队列中执行,不阻塞)
同步提交的任务在执行完成后才会返回 (提交任务后,只有执行完成之后才能继续进行,阻塞)
并行执行(全局队列)提交到一个队列的任务,比如提交了任务1和任务2,在任务1开始执行,并且没有执行完毕时候,任务2就可以开始执行。
串行执行(用户创建队列) 提交到一个队列中的任务,比如提交了任务1和任务2,只有任务1结束后,任务2才可执行
异步执行是两个队列之间的关系,并行执行是一个队列内部之间任务的关系
两个(多个)线程都要等待对方完成某个操作才能进行下一步,这时就会发生死锁。
3.在GCD中加入二个非常重要的概念:
任务和
队列。
任务的执行方式分为二种:
1.同步执行2.异步执行。他们之间的区别是:
是否会创建新的线程。
同步执行和异步执行的主要区别:同步执行(sync)会阻塞当前的线程并等待block中的任务执行完毕才会继续往下执行。异步执行(async)不会阻塞当前的线程,当前的线程直接往下执行。
队列
:用于存放任务。一共有两种队列,
串行队列
和
并行队列。
串行队列:
串行队列
中的任务会根据队列的定义 FIFO 的执行,一个接一个的先进先出的进行执行。放到串行队列的任务,GCD 会
FIFO(先进先出)
地取出来一个,执行一个,然后取下一个,这样一个一个的执行。
并行队列:放到并行队列的任务,GCD 也会
FIFO
的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行
主队列:这是一个特殊的
串行队列
:dispatch_queue_t queue =dispatch_get_main_queue();
自己可以创建 串行队列
, 也可以创建 并行队列
。它有两个参数,第一个队列的标识符,第二个才是最重要的。
第二个参数用来表示创建的队列是串行的还是并行的,传入
DISPATCH_QUEUE_SERIAL
或 NULL
表示创建串行队列。传入 DISPATCH_QUEUE_CONCURRENT
表示创建并行队列。
例如:自己创建的并行队列 dispatch_queue_t concurrentQueue = dispatch_queue_create("com.bjsxt.concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
全局并行队列:只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
具体的例子:
// dispatch_queue_t mainQueue = dispatch_get_main_queue();
// dispatch_sync(mainQueue,^{// (以为主线程是一个串行队列,线添加的代码先执行,而添加了一个同步的任务之后会阻塞到线程,等待同步任务里面都执行完之后在执行,所以造成互相等待,所以死锁)
// NSLog(@"MainQueue");
// });
// dispatch_queue_t serialQueue = dispatch_queue_create("com.dullgrass.serialQueue", DISPATCH_QUEUE_SERIAL);
// dispatch_sync(serialQueue, ^{ //该代码段后面的代码都不会执行,程序被锁定在这里
// NSLog(@"会执行的代码");
// dispatch_sync(serialQueue, ^{//两个(多个)线程都要等待对方完成某个操作才能进行下一步,这时就会发生死锁。将它放到block外面就能正常调用了
// NSLog(@"代码不执行");
// });
// });
// 主线成
// dispatch_queue_t mainQueue = dispatch_get_main_queue(); //因为是串行的所以按照顺序一个一个执行
// dispatch_async(mainQueue, ^{
// NSLog(@"1");
// NSLog(@"11");
// NSLog(@"111");
// NSLog(@"1111");
//
// });
// dispatch_async(mainQueue, ^{
// NSLog(@"2");
// });
// dispatch_async(mainQueue, ^{
// NSLog(@"3");
// });
// dispatch_async(mainQueue, ^{
// NSLog(@"4");
// });
全局并发线程
// dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_async(defaultQueue, ^{ //因为是并发的所以无需的执行,但是block里面是顺序执行。如果都改成sync就是按照顺序执行的了
// NSLog(@"g1");
// NSLog(@"g11");
// NSLog(@"g111");
// NSLog(@"g1111");
// });
// dispatch_async(defaultQueue, ^{
// NSLog(@"g2");
// });
// dispatch_async(defaultQueue, ^{
// NSLog(@"g3");
// });
// dispatch_async(defaultQueue, ^{
// NSLog(@"g4");
// });
//利用自定义队列可以模拟出 串行队列 并行队列 同步任务 异步任务
// 同步:无论是串行还是并行,都按照主线程顺序执行;
// 异步:串行的时候顺序执行,并行的时候无序执行;
// 串行:无论同步还是异步都顺序执行
// 并行:同步顺序执行,异步无序执行
// 自定义队列(在这因为是同步任务所以得等到block执行完毕之后才能进行下一步执行 NSLog(@"c6"); 但是如果改成async就会无序执行不会等待三秒,会先执行NSLog(@"c6");后执行NSLog(@"c5");)
// 自己创建的并行队列DISPATCH_QUEUE_CONCURRENT、串行队列DISPATCH_QUEUE_SERIAL(NULL)
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.bjsxt.concurrentQueuess", NULL);
dispatch_async(concurrentQueue, ^{//在这里要是改成sync 就会按照顺序一个一个执行下去 等待线程睡眠之后再执行
NSLog(@"c4");
dispatch_async(concurrentQueue, ^{//串行队列--这个改成sync会死锁,以为是串行队列,要等待异步任务里面都执行之后在执行其他的,而又因为同步的任务添加到里面,5要等待6执行完成之后在执行,而6又要等待5执行完成之后执行,从而造成死锁现象。
[NSThread sleepForTimeInterval:3];
NSLog(@"c5");
});
NSLog(@"c6");
});
dispatch_sync(concurrentQueue, ^{//如果改成sync,同步。。这样的话就会阻塞当前的线程(concurrentQueue),必须等到他执行完之后才能向下执行
NSLog(@"c7");//NSLog(@"c7")这个相当于是任务的执行代码,就是把打印的这句话放到concurrentQueue这个线程中去执行
});
dispatch_async(concurrentQueue, ^{
NSLog(@"c8");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"c9");
});
//1.创建队列组
dispatch_group_t group = dispatch_group_create();
//2.创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//3.多次使用队列组的方法执行任务, 只有异步方法,没有同步方法
//3.1.执行3次循环
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 3; i++) {
NSLog(@"group-01 - %@", [NSThread currentThread]);
}
});
//3.2.主队列执行8次循环
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 8; i++) {
NSLog(@"group-02 - %@", [NSThread currentThread]);
}
});
//3.3.执行5次循环
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"group-03 - %@", [NSThread currentThread]);
}
});
//4.都完成后会自动通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"完成 - %@", [NSThread currentThread]);
});
//延迟执行
// 创建队列
dispatch_queue_t queueG = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 设置延时,单位秒
double delay = 5;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queueG, ^{
// 3秒后需要执行的任务
NSLog(@"延迟执行操作");
});
// 我们都知道在其他线程操作完成后必须到主线程更新UI。所以,介绍完所有的多线程方案后,我们来看看有哪些方法可以回到主线程。
//Objective-C
// [self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];