iOS线程、同步异步、串行并行队列

线程与队列说不清道不明的关系:html

线程是代码执行的路径,队列则是用于保存以及管理任务的,线程负责去队列中取任务进行执行。 个人理解:多个队列的任务能够在一条线程上执行,一个队列的任务也能够在多条线程上执行。我的理解,队列能够包含线程,线程也能够包含队列。 ios

dispatch_sync:立马在当前线程执行任务,执行完再往下走,这句话就能够解释不少问题。程序员

dispatch_async:不要求立马在当前线程执行任务,可能会开启新线程,也有可能不会。安全

1、画图解释下队列跟线程间的关系

一、一个队列对应一个线程

"主队列" 对应 "主线程"bash

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blueColor];
    [self threadTest];
}
- (void)threadTest{
    NSLog(@"我是任务1");
    NSLog(@"我是任务2");
}
复制代码

二、一个队列对应两个线程

"队列1" 对应 "主线程"和"新线程" (由于主队列没有开启新线程的能力因此用"队列1")数据结构

- (void)threadTest{
    dispatch_queue_t queue = dispatch_queue_create("队列1", DISPATCH_QUEUE_SERIAL);
    //同步 不开启新线程,因此在主线程执行
    dispatch_sync(queue, ^{
        NSLog(@"任务1");
        [self getCurrentThread];
    });
    //异步 开启新线程
    dispatch_async(queue, ^{
        NSLog(@"任务2");//2️⃣
        [self getCurrentThread];
    });
    sleep(3);//若是没有这个方法,2️⃣3️⃣的执行前后顺序是不肯定的,由于是两个线程,执行前后没有一毛钱关系
    NSLog(@"方法执行结束");//3️⃣
}
- (void)getCurrentThread{
    NSThread *currentThread = [NSThread currentThread];
    NSLog(@"currentThread == %@",currentThread);
}
复制代码
2018-06-20 14:40:05.904914+0800 WLZCyclycReference[4497:158751] 任务1
2018-06-20 14:40:05.905099+0800 WLZCyclycReference[4497:158751] currentThread == <NSThread: 0x60800007c000>{number = 1, name = main}
2018-06-20 14:40:05.905230+0800 WLZCyclycReference[4497:158829] 任务2
2018-06-20 14:40:05.905381+0800 WLZCyclycReference[4497:158829] currentThread == <NSThread: 0x608000270800>{number = 3, name = (null)}
2018-06-20 14:40:08.906308+0800 WLZCyclycReference[4497:158751] 方法执行结束
复制代码

三、两个队列对应一个线程

"主队列"和"队列1" 对应 "主线程"多线程

- (void)threadTest{
    dispatch_queue_t queue = dispatch_queue_create("队列1", DISPATCH_QUEUE_SERIAL);
    NSLog(@"我是任务2");
    [self getCurrentThread];
    //同步 不开启新线程,因此在主线程执行
    dispatch_sync(queue, ^{
        sleep(3);//睡三秒能够解释不少问题
        NSLog(@"我是任务1");
        [self getCurrentThread];
    });
    NSLog(@"方法执行结束");
}
- (void)getCurrentThread{
    NSThread *currentThread = [NSThread currentThread];
    NSLog(@"currentThread == %@",currentThread);
}
复制代码
2018-06-20 14:53:39.210769+0800 WLZCyclycReference[4741:169494] 我是任务2
2018-06-20 14:53:39.210959+0800 WLZCyclycReference[4741:169494] currentThread == <NSThread: 0x608000065640>{number = 1, name = main}
2018-06-20 14:53:42.212170+0800 WLZCyclycReference[4741:169494] 我是任务1
2018-06-20 14:53:42.212615+0800 WLZCyclycReference[4741:169494] currentThread == <NSThread: 0x608000065640>{number = 1, name = main}
2018-06-20 14:53:42.212810+0800 WLZCyclycReference[4741:169494] 方法执行结束
复制代码

四、两个队列对应两个线程

"主队列"和"队列1" 对应 "主线程"和"新线程"并发

- (void)threadTest{
    dispatch_queue_t queue = dispatch_queue_create("队列1", DISPATCH_QUEUE_SERIAL);
    NSLog(@"我是任务2");
    [self getCurrentThread];
    //开启新线程
    dispatch_async(queue, ^{
        NSLog(@"我是任务1");//1️⃣
        [self getCurrentThread];
    });
    NSLog(@"方法执行结束");//2️⃣
    //1️⃣2️⃣的执行前后顺序是随机的
}
- (void)getCurrentThread{
    NSThread *currentThread = [NSThread currentThread];
    NSLog(@"currentThread == %@",currentThread);
}
复制代码
2018-06-20 15:11:12.132538+0800 WLZCyclycReference[5076:184244] 我是任务2
2018-06-20 15:11:12.132705+0800 WLZCyclycReference[5076:184244] currentThread == <NSThread: 0x60400007bd80>{number = 1, name = main}
2018-06-20 15:11:12.132809+0800 WLZCyclycReference[5076:184244] 方法执行结束
2018-06-20 15:11:12.132823+0800 WLZCyclycReference[5076:184332] 我是任务1
2018-06-20 15:11:12.133009+0800 WLZCyclycReference[5076:184332] currentThread == <NSThread: 0x6080002602c0>{number = 3, name = (null)}
复制代码

2、主线程特色讲解

主线程特色:若是主线程里有任务就必须等主线程任务执行完才轮到主队列(若是是其余队列的任务,那么任务就不用等待,会直接被主线程执行)的。因此说若是在主队列异步(开启新线程)执行任务无所谓,可是若是在主队列同步(不开启新线程,须要在主线程执行)执行任务会循环等待,形成死锁(可是在通常串行队列这样执行就不会出问题,一切都是由于主线程的这个特色)。app

一、主线程特色演示

dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(mainQueue, ^{
        NSLog(@"1");
        NSThread *mainThread = [NSThread currentThread];
        NSLog(@"currentThread == %@",mainQueue);
        sleep(3);
        NSLog(@"2");
    });
NSLog(@"主线程执行完了");
复制代码
2018-06-20 12:09:05.598367+0800 WLZCyclycReference[3254:101260] 主线程执行完了
2018-06-20 12:09:05.601950+0800 WLZCyclycReference[3254:101260] 1
2018-06-20 12:09:05.602095+0800 WLZCyclycReference[3254:101260] currentThread == <OS_dispatch_queue_main: com.apple.main-thread>
2018-06-20 12:09:08.603048+0800 WLZCyclycReference[3254:101260] 2
复制代码

从执行结果能够完美的看出主线程的特色,因此我严重怀疑:主队列的任务只能在主线程上执行,换句话说就是主队列是串行队列的阉割版,即主队列没有建立新线程的能力。异步

主线程在执行主队列任务的过程当中:

  • 若是主队列经过异步的方式添加"任务1",那么既然主队列没有开新线程的能力,就等我主线程把我当前的任务执行完了,我主线程再去执行"任务1";
  • 若是主队列经过同步的方式添加"任务2",那么我主线程仍是要先执行完我当前的任务,可是"任务2"是同步的,"任务2"又必需要主线程执行本身。那主线程只好循环等待而后死了。

二、主线程死锁演示,主线程产生死锁针对的是主队列

//主队列  同步执行任务  死锁
dispatch_sync(dispatch_get_main_queue(), ^{
});
复制代码

三、主线程中,一样的任务放到其它队列(串行、并行都可)同步执行,不会死锁,而且顺序执行,执行完“串行队列1”的任务,继续向下执行主队列的任务。

dispatch_queue_t queue = dispatch_queue_create("串行队列1", DISPATCH_QUEUE_SERIAL);
//串行队列  同步执行任务 由于没有开启线程因此仍是主线程
dispatch_sync(queue, ^{
});
复制代码

上述代码中"主队列"、"串行队列1"两个队列的任务互不干扰,这种状况其实就至关于把两个队列放到了一个更大的虚拟并行队列中,能够同时执行任务

FIFO,串行队列任务1没有执行完,同步执行任务2的话绝逼死锁,可是死锁产生的缘由是同一个队列里边的两个任务相互等待,若是不是同一个队列,那么久不会产生死锁。

四、同一个串行队列,同步执行任务嵌套,形成死锁。

dispatch_queue_t queue = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
//串行队列  同步执行任务 由于没有开启线程因此仍是主线程
dispatch_sync(queue, ^{
    NSLog(@"1");
    dispatch_sync(queue, ^{
        NSLog(@"串行队列嵌套执行");
    });
    NSLog(@"2");
});
复制代码

上边死锁的状况能够说明一个问题,某一个串行队列正在执行一个同步任务,这时候又在当前队列插入了一个同步任务就会形成死锁。这种状况就跟1(主队列有任务,主线程执行ing,主队列插入同步任务形成死锁)的状况是同样的,只不过主队列是系统自带的,咱们这个队列是本身建立的而已。

同步异步:指的是函数(方法),可否开启新的线程。同步不能,异步能够

串行并行:指的是队列,任务的执行方式,串行指各个任务按顺序执行。并行指多个任务能够同时执行

串行队列也能够开启新的线程,只不过开启以后也只是按顺序执行,

3、概念解释

如下概念参考"08号疯子"的博客: IOS多线程知识总结/队列概念/GCD/串行/并行/同步/异步

  • 进程:正在进行中的程序被称为进程,负责程序运行的内存分配;每个进程都有本身独立的虚拟内存空间;

  • 线程:线程是进程中一个独立的执行路径(控制单元);一个进程中至少包含一条线程,即主线程。

  • 队列:dispatch_queue_t,一种先进先出的数据结构,线程的建立和回收不须要程序员操做,由队列负责。

  • 队列-串行队列:队列中的任务只会顺序执行

dispatch_queue_t q = dispatch_queue_create(“....”, dispatch_queue_serial);

  • 队列-并行队列:队列中的任务一般会并发执行

dispatch_queue_t q = dispatch_queue_create("......", dispatch_queue_concurrent);

  • 队列-全局队列:是系统开发的,直接拿过来(get)用就能够;与并行队列相似,但调试时,没法确认操做所在队列  

dispatch_queue_t q = dispatch_get_global_queue(dispatch_queue_priority_default, 0);

  • 队列-主队列:每个应用程序对应惟一一个主队列,直接get便可;在多线程开发中,使用主队列更新UI

dispatch_queue_t q = dispatch_get_main_queue();

  • 串行队列同步:操做不会新建线程、操做顺序执行;

  • 串行队列异步:操做须要一个子线程,会新建线程、线程的建立和回收不须要程序员参与,操做顺序执行,是最安全的选择;

  • 并行队列同步:操做不会新建线程、操做顺序执行;

  • 并行队列异步:操做会新建多个线程(有多少任务,就开n个线程执行)、操做无序执行;队列前若是有其余任务,会等待前面的任务完成以后再执行;场景:既不影响主线程,又不须要顺序执行的操做

  • 全局队列同步:操做不会新建线程、操做顺序执行;

  • 全局队列异步:操做会新建多个线程、操做无序执行,队列前若是有其余任务,会等待前面的任务完成以后再执行;

  • 主局队列同步:若是把主线程中的操做当作一个大的block,那么除非主线程被用户杀掉,不然永远不会结束;主队列中添加的同步操做永远不会被执行,会死锁;

  • 主局队列异步:操做都应该在主线程上顺序执行的,不存在异步的;

一、队列和线程的区别:

队列:是管理线程的,至关于线程池,能管理线程何时执行。

队列分为串行队列和并行队列:

串行队列:队列中的线程按顺序执行(不会同时执行)

并行队列:队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗,若是后面的任务执行完了,怎么出去的了。这里须要强调下,任务执行完毕了,不必定出队列。只有前面的任务执行完了,才会出队列。

二、主线程队列和gcd建立的队列也是有区别的。

主线程队列和gcd建立的队列是不一样的。在gcd中建立的队列优先级没有主队列高,因此在gcd中的串行队列开启同步任务里面没有嵌套任务是不会阻塞主线程,只有一种可能致使死锁,就是串行队列里,嵌套开启任务,有可能会致使死锁。

主线程队列中不能开启同步,会阻塞主线程。只能开启异步任务,开启异步任务也不会开启新的线程,只是下降异步任务的优先级,让cpu空闲的时候才去调用。而同步任务,会抢占主线程的资源,会形成死锁。

三、线程:里面有很是多的任务(同步,异步)

同步与异步的区别:

同步任务优先级高,在线程中有执行顺序,不会开启新的线程。

异步任务优先级低,在线程中执行没有顺序,看cpu闲不闲。在主队列中不会开启新的线程,其余队列会开启新的线程。

四、主线程队列注意:

在主队列开启异步任务,不会开启新的线程而是依然在主线程中执行代码块中的代码。为何不会阻塞线程?

主队列开启异步任务,虽然不会开启新的线程,可是他会把异步任务下降优先级,等闲着的时候,就会在主线程上执行异步任务。

在主队列开启同步任务,为何会阻塞线程?

在主队列开启同步任务,由于主队列是串行队列,里面的线程是有顺序的,先执行完一个线程才执行下一个线程,而主队列始终就只有一个主线程,主线程是不会执行完毕的,由于他是无限循环的,除非关闭应用开发程序。所以在主线程开启一个同步任务,同步任务会想抢占执行的资源,而主线程任务一直在执行某些操做,不愿放手。两个的优先级都很高,最终致使死锁,阻塞线程了。

相关文章
相关标签/搜索