澳门威利斯人_威利斯人娱乐「手机版」

来自 网络资讯 2020-04-16 19:28 的文章
当前位置: 澳门威利斯人 > 网络资讯 > 正文

多线程之GCD,iOS多线程小结

  • 联手串行:不开启线程
  • 同台并行:不开启线程
  • 异步串行:最多展开叁个线程
  • 异步并行:开启线程

在学习Android编制程序的时候,大家日常会使用 runOnUiThread(),把UI相关的操作放到里面。而有的耗费时间的操作,则停放一个新的后台线程,但在iOS在接纳GCD的时候,大家把定义的任务增加到适当的Dispatch Queue中Dispatch以FIFO(先进先出,First-In-First-Out卡塔尔国的顺序施行义务。在iOS中有二种队列,分别是串行队列和现身队列。串行队列,很显然贰遍只可以实践一个职责,而并发队列则能够一次性施行多个职分。iOS 系统正是运用这个队列来开展职分调治的,它会基于调解职分的内需和系统当下的负载情状动态地开创和销毁线程,而无需大家手动地保管。

参考:
GCD源码
浓重了然 GCD
iOS多线程--深透学会四线程之『GCD』
有关iOS八十二二十四线程,笔者说,你听,没准你就懂了

在攻读GCD以前,作者以为要求了然多少个宗旨的定义

任务实践办法

  • 联机试行(dispatch_sync):只好在近些日子线程中施行职务,不具备开启新线程的力量。必需等到Block函数实行完结后,dispatch函数才会回去。
  • 异步实践(dispatch_async):能够在新的线程中实施义务,具有开启新线程的本事。dispatch函数会即刻回去, 然后Block在后台异步实施。
  • 协助举行:不开启线程,并将增添时域信号锁。同步会拥塞当前线程
  • 异步:能够开启线程
  • 串行:职务一个叁个奉行
  • 相互影响:义务毫无贰个一个施行

在队列中,选拔先进先出的艺术从RunLoop抽出职务

职分管理措施

  • 串行队列:全部职分会在一条线程中施行(有相当的大可能率是日前线程也是有相当大希望是新开荒的线程),何况二个义务推行实现后,才开头施行下叁个义务。(等待达成)
  • 彼此队列:能够拉开多条线程并行奉行义务(但不自然会敞开新的线程),况且当七个职务放到钦赐线程开端实行时,下二个任务就能够起来实行了。(等待发生)
    // 主队列--串行,所有放在主队列中的任务,都会放到主线程中执行
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    // 全局队列--并行,系统为我们创建好的一个并行队列,使用起来与我们自己创建的并行队列无本质差别
    dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);

    // new串行队列
    dispatch_queue_t queue1 = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);

    // new并行队列
    dispatch_queue_t queue2 = dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);

注意:防止选取 GCD Global队列创制Runloop常驻线程
全局队列的尾部是二个线程池,向全局队列中付出的 block,都会被停放那个线程池中执行,即便线程池已满,后续再交由 block 就不会再重新创制线程。等待有空闲的线程在实施职务。
所以:
幸免选用 GCD Global 队列创立 Runloop 常驻线程,如若n条线程都被并吞了,Global队列就费了。

线程死锁

在四个线程中多个串行队列中多个一块任务相互等待出现线程死锁

- test1{ dispatch_queue_t queueSerial = dispatch_queue_create("queueSerial", DISPATCH_QUEUE_SERIAL); /** 同步队列中两个任务相互等待 */ dispatch_sync(queueSerial, ^{ dispatch_sync(queueSerial, ^{ }); });}- test2{ /** 主队列中两个任务相互等待 */ dispatch_sync(dispatch_get_main_queue(), ^{ NSLog; });}- test3{ /** 两个队列中任务相互等待 */ dispatch_queue_t queueSerialOne = dispatch_queue_create("queueSerial", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queueSerialTwo = dispatch_queue_create("queueSerial", DISPATCH_QUEUE_SERIAL); dispatch_sync(queueSerialOne, ^{ dispatch_sync(queueSerialTwo, ^{ dispatch_sync(queueSerialOne, ^{ }); }); });}

死锁解释:同步开启信号量,时限信号量的 被压到了最下边

 dispatch_async(queue, ^{ dispatch_semaphore_signal(semaphore); });

图片 1SerialDispatchQueue.png

任务 队列

串行队列 并行队列 主队列
同步(sync) 当前线程,串行执行 队列当前线程,串行执行 主新线程,串行执行(注意死锁)
异步(async) 开1条新线程,串行执行 开n条新线程,异步执行(n在iphone7上面最大是几十个) 主新线程,串行执行

延期施行

暗中认可格局是异步,使用主要队列会在主线程中推行使用串行队列会开启线程

- test4{ dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (2.0 * NSEC_PER_SEC)); dispatch_queue_t queueSerialOne = dispatch_queue_create("queueSerial", DISPATCH_QUEUE_SERIAL); dispatch_after(time, queueSerialOne, ^{ });}

一致,在竞相队列此中,依旧也是使用先进先出的章程从RunLoop抽取来

Dispatch Block

队列实施职务都以block的不二等秘书诀,

dispatch_group_t: 可以隔开当前线程,当有着任务成功时在往下施行dispatch_group_notify: 能够不打断当前线程

- test5{ dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT); dispatch_group_async(group, queue, ^{ }); dispatch_group_wait(group, DISPATCH_TIME_FOREVER);}- test6{ dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_async(group, queue, ^{ }); dispatch_group_notify(group, queue, ^{ });}

图片 2concurrentDispatchQueue.png

创建block
- (void)createDispatchBlock {
    // 一般的block
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.starming.gcddemo.concurrentqueue",DISPATCH_QUEUE_CONCURRENT);
    dispatch_block_t block = dispatch_block_create(0, ^{
        NSLog(@"run block");
    });
    dispatch_async(concurrentQueue, block);

    //QOS优先级的block
    dispatch_block_t qosBlock = dispatch_block_create_with_qos_class(0, QOS_CLASS_USER_INITIATED, -1, ^{
        NSLog(@"run qos block");
    });
    dispatch_async(concurrentQueue, qosBlock);
}

dispatch_block_wait:可以根据dispatch block来安装等待时间,参数DISPATCH_TIME_FOREVE智跑会一向等待block停止

- (void)dispatchBlockWaitDemo {
    dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);
    dispatch_block_t block = dispatch_block_create(0, ^{
        NSLog(@"star");
        [NSThread sleepForTimeInterval:5.f];
        NSLog(@"end");
    });
    dispatch_async(serialQueue, block);
    //设置DISPATCH_TIME_FOREVER会一直等到前面任务都完成
    dispatch_block_wait(block, DISPATCH_TIME_FOREVER);
    NSLog(@"ok, now can go on");
}

dispatch_block_notify:能够监视钦命dispatch block甘休,然后再参与三个block到行列中。多个参数分别为,第叁个是内需监视的block,第三个参数是供给交给施行的种类,第多少个是待参与到行列中的block

- (void)dispatchBlockNotifyDemo {
    dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);
    dispatch_block_t firstBlock = dispatch_block_create(0, ^{
        NSLog(@"first block start");
        [NSThread sleepForTimeInterval:2.f];
        NSLog(@"first block end");
    });
    dispatch_async(serialQueue, firstBlock);
    dispatch_block_t secondBlock = dispatch_block_create(0, ^{
        NSLog(@"second block run");
    });
    //first block执行完才在serial queue中执行second block
    dispatch_block_notify(firstBlock, serialQueue, secondBlock);
}

dispatch_block_cancel:iOS8从今以往方可调用dispatch_block_cancel来裁撤(供给在乎必得用dispatch_block_create创建dispatch_block_t)
须求注意的是,未进行的能够用此办法cancel掉,若已经施行则cancel不了
一旦想中断(interrupt)线程,能够应用dispatch_block_testcancel方法

- (void)dispatchBlockCancelDemo {
    dispatch_queue_t serialQueue = dispatch_queue_create("com.starming.gcddemo.serialqueue", DISPATCH_QUEUE_SERIAL);
    dispatch_block_t firstBlock = dispatch_block_create(0, ^{
        NSLog(@"first block start");
        [NSThread sleepForTimeInterval:2.f];
        NSLog(@"first block end");
    });
    dispatch_block_t secondBlock = dispatch_block_create(0, ^{
        NSLog(@"second block run");
    });
    dispatch_async(serialQueue, firstBlock);
    dispatch_async(serialQueue, secondBlock);
    //取消secondBlock
    dispatch_block_cancel(secondBlock);
}

屡屡施行

dispatch_apply: 会堵塞当前线程

- test7{ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(10, queue, ^ { });}

还要还索要弄领会下边三种实行形式

1. 串行队列 同步进行

不会张开新线程,在时下线程实施任务。任务是串行的,施行完叁个职分,再实施下一个义务

- (void)serialQueueSync{

    NSLog(@"0========%@",[NSThread currentThread]);
    dispatch_queue_t serialQueue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(serialQueue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
    });
    dispatch_sync(serialQueue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    dispatch_sync(serialQueue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
    });
    NSLog(@"4========%@",[NSThread currentThread]);

    /*
     NSLog输出
     0========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     1========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     2========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     3========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     4========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     */

}

队列特有数量

- test8{ dispatch_queue_t queueA = dispatch_queue_create("queueA", NULL); dispatch_queue_t queueB = dispatch_queue_create("queueB", NULL); dispatch_set_target_queue(queueB, queueA); static int kQeueueSpecific; CFStringRef queueSpecificValue = CFSTR; dispatch_queue_set_specific(queueA, &kQeueueSpecific, queueSpecificValue, (dispatch_function_t)CFRelease); dispatch_sync(queueB, ^{ dispatch_block_t block = ^{ NSLog; }; CFStringRef retrievedValue = dispatch_get_specific(&kQeueueSpecific); if (retrievedValue) { block(); }else{ dispatch_sync(queueA, block); } });}
  • 串行队列中通过异步开启线程,最四只可以张开贰个
  • 串行队列的末尾有非信号量,须要静观其变实践到位后,本领往下三个施行
  • 在一个线程中三个串行队列中七个一块任务相互等待现身线程死锁,时域信号量的 被压到了最上边
  • 异步决定是不是开启线程,而且是或不是展开复信号量
  • 串行队列遵照顺序推行
  • 一道下义务相互等待会促成线程死锁
- opration{ // 在当前线程使用子类 NSInvocationOperation [self useInvocationOperation]; // 在其他线程使用子类 NSInvocationOperation // [NSThread detachNewThreadSelector:@selector(useInvocationOperation) toTarget:self withObject:nil]; // 在当前线程使用 NSBlockOperation // [self useBlockOperation]; // 使用 NSBlockOperation 的 AddExecutionBlock: 方法 // [self useBlockOperationAddExecutionBlock]; // 使用自定义继承自 NSOperation 的子类 // [self useCustomOperation]; // 使用addOperation: 添加操作到队列中 // [self addOperationToQueue]; // 使用 addOperationWithBlock: 添加操作到队列中 // [self addOperationWithBlockToQueue]; // 设置最大并发操作数(MaxConcurrentOperationCount) // [self setMaxConcurrentOperationCount]; // 设置优先级 // [self setQueuePriority]; // 添加依赖 // [self addDependency]; // 线程间的通信 // [self communication]; // 完成操作 // [self completionBlock]; // 不考虑线程安全 // [self initTicketStatusNotSave]; // 考虑线程安全 // [self initTicketStatusSave];}

- useInvocationOperation { // 1.创建 NSInvocationOperation 对象 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector object:nil]; // 2.调用 start 方法开始执行操作 [op start];}

- useBlockOperation { // 1.创建 NSBlockOperation 对象 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } }]; // 2.调用 start 方法开始执行操作 [op start];}
  • 使用子类 NSBlockOperation
  • 调用方法 AddExecutionBlock:
- useBlockOperationAddExecutionBlock { // 1.创建 NSBlockOperation 对象 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } }]; // 2.添加额外的操作 [op addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 } }]; [op addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程 } }]; [op addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程 } }]; [op addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"5---%@", [NSThread currentThread]); // 打印当前线程 } }]; [op addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"6---%@", [NSThread currentThread]); // 打印当前线程 } }]; [op addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"7---%@", [NSThread currentThread]); // 打印当前线程 } }]; [op addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"8---%@", [NSThread currentThread]); // 打印当前线程 } }]; // 3.调用 start 方法开始执行操作 [op start];}

- useCustomOperation { // 1.创建 YSCOperation 对象 YSCOperation *op = [[YSCOperation alloc] init]; // 2.调用 start 方法开始执行操作 [op start];}

- addOperationToQueue { // 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.创建操作 // 使用 NSInvocationOperation 创建操作1 NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector object:nil]; // 使用 NSInvocationOperation 创建操作2 NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector object:nil]; // 使用 NSBlockOperation 创建操作3 NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程 } }]; [op3 addExecutionBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程 } }]; // 3.使用 addOperation: 添加所有操作到队列中 [queue addOperation:op1]; // [op1 start] [queue addOperation:op2]; // [op2 start] [queue addOperation:op3]; // [op3 start]}

- addOperationWithBlockToQueue { // 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.使用 addOperationWithBlock: 添加操作到队列中 [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程 } }];}

- setMaxConcurrentOperationCount { // 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.设置最大并发操作数 queue.maxConcurrentOperationCount = 1; // 串行队列 // queue.maxConcurrentOperationCount = 2; // 并发队列 // queue.maxConcurrentOperationCount = 8; // 并发队列 // 3.添加操作 [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程 } }];}
  • 稳妥状态下,优先级高的会事情发生前履行,但是执行时间长短而不是迟早的,所以优先级高的实际不是早晚上的集会先进行达成
- setQueuePriority{ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { NSLog(@"1-----%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:2]; } }]; [op1 setQueuePriority:(NSOperationQueuePriorityVeryLow)]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { NSLog(@"2-----%@", [NSThread currentThread]); [NSThread sleepForTimeInterval:2]; } }]; [op2 setQueuePriority:(NSOperationQueuePriorityVeryHigh)]; [queue addOperation:op1]; [queue addOperation:op2];}
  • 接受方法:addDependency:
- addDependency { // 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.创建操作 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 } }]; // 3.添加依赖 [op2 addDependency:op1]; // 让op2 依赖于 op1,则先执行op1,在执行op2 // 4.添加操作到队列中 [queue addOperation:op1]; [queue addOperation:op2];}

- communication { // 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; // 2.添加操作 [queue addOperationWithBlock:^{ // 异步进行耗时操作 for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } // 回到主线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 进行一些 UI 刷新等操作 for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 } }]; }];}

- completionBlock { // 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.创建操作 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } }]; // 3.添加完成操作 op1.completionBlock = ^{ for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 } }; // 4.添加操作到队列中 [queue addOperation:op1];}
  • 非线程安全:不使用 NSLock
  • 开首化火车票的数量量、卖票窗口、并开头卖票
- initTicketStatusNotSave { NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程 self.ticketSurplusCount = 50; // 1.创建 queue1,queue1 代表北京火车票售卖窗口 NSOperationQueue *queue1 = [[NSOperationQueue alloc] init]; queue1.maxConcurrentOperationCount = 1; // 2.创建 queue2,queue2 代表上海火车票售卖窗口 NSOperationQueue *queue2 = [[NSOperationQueue alloc] init]; queue2.maxConcurrentOperationCount = 1; // 3.创建卖票操作 op1 __weak typeof weakSelf = self; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ [weakSelf saleTicketNotSafe]; }]; // 4.创建卖票操作 op2 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ [weakSelf saleTicketNotSafe]; }]; // 5.添加操作,开始卖票 [queue1 addOperation:op1]; [queue2 addOperation:op2];}

- saleTicketNotSafe { while  { if (self.ticketSurplusCount > 0) { //如果还有票,继续售卖 self.ticketSurplusCount--; NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]); [NSThread sleepForTimeInterval:0.2]; } else { NSLog(@"所有火车票均已售完"); break; } }}
  • 初叶化学轻工轨票的数量量、卖票窗口、并初叶卖票
- initTicketStatusSave { NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程 self.ticketSurplusCount = 50; self.lock = [[NSLock alloc] init]; // 1.创建 queue1,queue1 代表北京火车票售卖窗口 NSOperationQueue *queue1 = [[NSOperationQueue alloc] init]; queue1.maxConcurrentOperationCount = 1; // 2.创建 queue2,queue2 代表上海火车票售卖窗口 NSOperationQueue *queue2 = [[NSOperationQueue alloc] init]; queue2.maxConcurrentOperationCount = 1; // 3.创建卖票操作 op1 __weak typeof weakSelf = self; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ [weakSelf saleTicketSafe]; }]; // 4.创建卖票操作 op2 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ [weakSelf saleTicketSafe]; }]; // 5.添加操作,开始卖票 [queue1 addOperation:op1]; [queue2 addOperation:op2];}

- saleTicketSafe { while  { // 加锁 [self.lock lock]; if (self.ticketSurplusCount > 0) { //如果还有票,继续售卖 self.ticketSurplusCount--; NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]); [NSThread sleepForTimeInterval:0.2]; } // 解锁 [self.lock unlock]; if (self.ticketSurplusCount <= 0) { NSLog(@"所有火车票均已售完"); break; } }}/** * 任务1 */- task1 { for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 }}/** * 任务2 */- task2 { for (int i = 0; i < 2; i  ) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 }}

下载

异步实践,不会卡住当前线程。

2. 串行队列 异步试行

开贰个新线程,叁个一个执行任务

    NSLog(@"0========%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
    });
    NSLog(@"4========%@",[NSThread currentThread]);

    /*
     NSLog输出
     0========<NSThread: 0x6000002616c0>{number = 1, name = main}
     4========<NSThread: 0x6000002616c0>{number = 1, name = main}
     1========<NSThread: 0x608000270540>{number = 3, name = (null)}
     2========<NSThread: 0x608000270540>{number = 3, name = (null)}
     3========<NSThread: 0x608000270540>{number = 3, name = (null)}
     */

一齐施行,会梗塞当前线程,直到近期的block职责实践完结。

3. 并行队列 同步执行

一时线程,一个二个实施职分

    NSLog(@"0========%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
    });
    NSLog(@"4========%@",[NSThread currentThread]);

    /*
     NSLog输出
     0========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     1========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     2========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     3========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     4========<NSThread: 0x60800007f840>{number = 3, name = (null)}
     */

相通,在产出队列中,采取一块进行,会有啥样的结果吗?

4. 并行队列 异步实行

开七个线程,异步实行

    NSLog(@"0========%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
    });
    NSLog(@"4========%@",[NSThread currentThread]);

    /*
     NSLog输出
     0========<NSThread: 0x608000070300>{number = 1, name = main}
     4========<NSThread: 0x608000070300>{number = 1, name = main}
     2========<NSThread: 0x608000264140>{number = 4, name = (null)}
     1========<NSThread: 0x60000007a800>{number = 3, name = (null)}
     3========<NSThread: 0x6080002642c0>{number = 5, name = (null)}
     */

本条比较容易,会拥塞当前线程。

5. 主队列 异步推行

主线程,同步实行

    NSLog(@"0========%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
    });
    NSLog(@"4========%@",[NSThread currentThread]);

    /*
     NSLog输出
     0========<NSThread: 0x60000026e000>{number = 3, name = (null)}
     4========<NSThread: 0x60000026e000>{number = 3, name = (null)}
     1========<NSThread: 0x60000007e2c0>{number = 1, name = main}
     2========<NSThread: 0x60000007e2c0>{number = 1, name = main}
     3========<NSThread: 0x60000007e2c0>{number = 1, name = main}
     */

1、同步和异步决定了是或不是张开新的线程。main队列除此之外,在main队列中,同步照旧异步实践都会窒碍当线的main线程,且不会另开线程。当然,永恒不要选用sync向主队列中增添义务,那样子会线程卡死,具体原因看main线程。

6. 主队列 同步奉行 (不能在主队列这么用,死锁)

主线程,同步推行

    NSLog(@"0========%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"1========%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2========%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3========%@",[NSThread currentThread]);
    });
    NSLog(@"4========%@",[NSThread currentThread]);

    /*
     NSLog输出
     0========<NSThread: 0x600000263840>{number = 3, name = (null)}
     1========<NSThread: 0x608000078ec0>{number = 1, name = main}
     2========<NSThread: 0x608000078ec0>{number = 1, name = main}
     3========<NSThread: 0x608000078ec0>{number = 1, name = main}
     4========<NSThread: 0x600000263840>{number = 3, name = (null)}
     */

2、串行和相互作用,决定了任务是还是不是还要推行。

GCD其余用法

dispatch_queue_t queue = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_after延时

1、time = 0,是直接调用异步dispatch_async
2、time > 0, 只是延时提交block,不是延时随时执行。

    //2秒延时、在主队列
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

    });

第一个参数钦点该队列的称号,该名称会晤世应用程序崩溃时发生的CrashLog中,在调用进度中大家也足以行使dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)取得当前队列的名字。

dispatch_once与dispatch_once_t
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //
    });

1、dispatch_once并非大概的只进行壹回那么粗略
2、dispatch_once本质上得以接收屡屡伸手,会对此维护三个诉求链表
3、倘若在block施行时期,数次进去调用同类的dispatch_once函数(即单例函数),会以致全体链表Infiniti增加,变成永世性死锁。

递归相互嵌套,如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ // 链表无限增长
        [self viewDidLoad];
    });
}

dispatch_once源码

static void
dispatch_once_f_slow(dispatch_once_t *val, void *ctxt, dispatch_function_t func)
{
#if DISPATCH_GATE_USE_FOR_DISPATCH_ONCE
    dispatch_once_gate_t l = (dispatch_once_gate_t)val;

    if (_dispatch_once_gate_tryenter(l)) {
        _dispatch_client_callout(ctxt, func);
        _dispatch_once_gate_broadcast(l);
    } else {
        _dispatch_once_gate_wait(l);
    }
#else
    _dispatch_once_waiter_t volatile *vval = (_dispatch_once_waiter_t*)val;
    struct _dispatch_once_waiter_s dow = { };
    _dispatch_once_waiter_t tail = &dow, next, tmp;
    dispatch_thread_event_t event;


    if (os_atomic_cmpxchg(vval, NULL, tail, acquire)) {

        // 第一次dispatch_once,原子性操作

        // 当前线程
        dow.dow_thread = _dispatch_tid_self();
        // 执行block
        _dispatch_client_callout(ctxt, func);

        // 第一次执行完了,设置token = DISPATCH_ONCE_DONE
        next = (_dispatch_once_waiter_t)_dispatch_once_xchg_done(val);
        while (next != tail) {

            // 继续去下一个
            tmp = (_dispatch_once_waiter_t)_dispatch_wait_until(next->dow_next);
            event = &next->dow_event;
            next = tmp;

            // 信号量  
            _dispatch_thread_event_signal(event);
        }
    } else {

        // 第二次dispatch_once进来
        _dispatch_thread_event_init(&dow.dow_event);
        next = *vval;
        for (;;) {
            if (next == DISPATCH_ONCE_DONE) { // token是否等于DISPATCH_ONCE_DONE
                // 第一次执行完之后,都是走这里
                break;
            }
            // 如果是嵌套使用,第一次没有完成,又要执行一次
            if (os_atomic_cmpxchgv(vval, next, tail, &next, release)) {
                // 原子性
                dow.dow_thread = next->dow_thread;
                dow.dow_next = next;
                if (dow.dow_thread) {
                    pthread_priority_t pp = _dispatch_get_priority();
                    _dispatch_thread_override_start(dow.dow_thread, pp, val);
                }
                // 等待信号量
                _dispatch_thread_event_wait(&dow.dow_event);
                if (dow.dow_thread) {
                    _dispatch_thread_override_end(dow.dow_thread, val);
                }
                break;
            }
        }
        _dispatch_thread_event_destroy(&dow.dow_event);
    }
#endif
}

第三个参数钦命该队列的品种。

dispatch_apply(count,queue,block(index卡塔尔(قطر‎卡塔尔国迭代艺术

该函数按内定的次数将钦定的block追加到钦点的队列;使用的地点,堵塞当前线程

    NSLog(@"CurrentThread------%@", [NSThread currentThread]);
    //dispatch_queue_t queue = dispatch_get_global_queue(0,0);
    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
    // 6是次数
    dispatch_apply(6, queue, ^(size_t index) {
        NSLog(@"%zd------%@",index, [NSThread currentThread]);
    });
    /*
     并发队列:开多线程异步执行
     NSLogx信息
     CurrentThread------<NSThread: 0x600000268a40>{number = 3, name = (null)}
     0------<NSThread: 0x600000268a40>{number = 3, name = (null)}
     1------<NSThread: 0x608000266e40>{number = 4, name = (null)}
     2------<NSThread: 0x608000266f00>{number = 5, name = (null)}
     3------<NSThread: 0x608000266f40>{number = 6, name = (null)}
     4------<NSThread: 0x600000268a40>{number = 3, name = (null)}
     5------<NSThread: 0x608000266e40>{number = 4, name = (null)}
     */


    /*
     同步队列:当前线程同步执行
     NSLogx信息
     CurrentThread------<NSThread: 0x608000072c00>{number = 3, name = (null)}
     0------<NSThread: 0x6000000694c0>{number = 1, name = main}
     1------<NSThread: 0x6000000694c0>{number = 1, name = main}
     2------<NSThread: 0x6000000694c0>{number = 1, name = main}
     3------<NSThread: 0x6000000694c0>{number = 1, name = main}
     4------<NSThread: 0x6000000694c0>{number = 1, name = main}
     5------<NSThread: 0x6000000694c0>{number = 1, name = main}
     */

dispatch_apply能制止线程爆炸,因为GCD会管理现身

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 999; i  ){
      dispatch_async(queue, ^{
         NSLog(@"%d,%@",i,[NSThread currentThread]);// 能开多大线程就开多大线程(几十个)
      });
}

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(999, queue, ^(size_t i){
     NSLog(@"%d,%@",i,[NSThread currentThread]); // 只开一定数量的线程(几个)
});

DISPATCH_QUEUE_SERIAL或者NULL表示该队列是串行队列,

dispatch_suspend、dispatch_resume (用在dispatch_get_global_queue主队列无效State of Qatar

dispatch_suspend,dispatch_resume提供了“挂起、恢复生机”队列的魔法,轻巧的话,正是能够暂停、苏醒队列上的职务。不过此间的“挂起”,并不能够保障能够立时终止队列上正在运维的block

注意点:

本文由澳门威利斯人发布于网络资讯,转载请注明出处:多线程之GCD,iOS多线程小结

关键词: 澳门威利斯人 IOS 多线程 小结 GCD