iOS 多线程再探

2022-03-24 08:42:08 浏览数 (1)

一.队列 同步异步

关于这个我在前面的文章也写过,这里写个例子复习一下

代码语言:javascript复制
1).串行队列同步执行:任务都在当前线程执行(同步),并且顺序执行(串行)
2).串行队列异步执行:任务都在开辟的新的子线程中执行(异步),并且顺序执行(串行)
3).并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)
4).并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)
代码语言:javascript复制
-(void)testCon_queue{
    dispatch_queue_t con_queue = dispatch_queue_create("con", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(con_queue, ^{
        dispatch_async(con_queue, ^{
            NSLog(@"1----%@",NSThread.currentThread);
        });
        
        dispatch_sync(con_queue, ^{
            NSLog(@"2----%@",NSThread.currentThread);
        });
        
        dispatch_sync(con_queue, ^{
            NSLog(@"3----%@",NSThread.currentThread);
        });
        
        dispatch_async(con_queue, ^{
            NSLog(@"4----%@",NSThread.currentThread);
        });
        
        dispatch_async(con_queue, ^{
            NSLog(@"5----%@",NSThread.currentThread);
        });
        
        dispatch_async(con_queue, ^{
            NSLog(@"6----%@",NSThread.currentThread);
        });
    });
    
}
代码语言:javascript复制
1----<NSThread: 0x600001f8d580>{number = 4, name = (null)}
2----<NSThread: 0x600001f98fc0>{number = 3, name = (null)}
3----<NSThread: 0x600001f98fc0>{number = 3, name = (null)}
4----<NSThread: 0x600001f98fc0>{number = 3, name = (null)}
5----<NSThread: 0x600001f98fc0>{number = 3, name = (null)}
6----<NSThread: 0x600001f8d580>{number = 4, name = (null)}
代码语言:javascript复制
2----<NSThread: 0x6000011af380>{number = 3, name = (null)}
1----<NSThread: 0x6000011aa780>{number = 4, name = (null)}
3----<NSThread: 0x6000011af380>{number = 3, name = (null)}
5----<NSThread: 0x6000011aa780>{number = 4, name = (null)}
6----<NSThread: 0x6000011aa1c0>{number = 5, name = (null)}
4----<NSThread: 0x6000011af380>{number = 3, name = (null)}

解释一下,1 4 5 6是并发队列异步执行,所以他们会在开辟的新线程中并行执行,谁先谁后不一定。符合

代码语言:javascript复制
4).并发队列异步执行:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)

2 3是并发队列同步执行,他们在同一条线程上顺序执行,如结果所示,线程number=3,2了才3。符合

代码语言:javascript复制
3).并发队列同步执行:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)

我们在上两个结果中也能看见,有异步任务的执行线程跟同步任务执行的线程相同,也有两个异步任务的执行线程相同,这是因为一旦线程任务完成,其他任务可能会复用这条线程,有线程池维护它们,没有必要创建过多的线程造成资源浪费

二.队列 同步异步 信号量

1.并发队列同步

代码语言:javascript复制
-(void)testSem{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_async(queue, ^{
        NSLog(@"1---%@",NSThread.currentThread);
        
        dispatch_sync(queue, ^{
            [self netWork_task_requestTime:2 completionHandle:^{
                NSLog(@"2---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"3---%@",NSThread.currentThread);
            
        });
        
        dispatch_sync(queue, ^{
            [self netWork_task_requestTime:1 completionHandle:^{
                NSLog(@"4---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"5---%@",NSThread.currentThread);
        });
        
        NSLog(@"6---%@",NSThread.currentThread);

    });
}

- (void)netWork_task_requestTime:(int)time completionHandle:(void(^)(void))success {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        success();
    });
}

image.png

解释:信号量初始为0,1输出,执行2后wait,把3和以后的阻塞,2秒后主线程返回,任务完成signal,信号量 1,继续往下执行。 第二个同步任务与第一个执行情况一样:执行4后wait,5和以后的阻塞,1秒后主线程返回,任务完成signal,信号量 1,继续往下执行。 因为是同步执行,所以6最后输出

2.并发队列异步 我们把代码改成如下:

代码语言:javascript复制
-(void)testSem{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_async(queue, ^{
        NSLog(@"1---%@",NSThread.currentThread);
        
        dispatch_async(queue, ^{
            [self netWork_task_requestTime:2 completionHandle:^{
                NSLog(@"2---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"3---%@",NSThread.currentThread);
            
        });
        
        dispatch_async(queue, ^{
            [self netWork_task_requestTime:1 completionHandle:^{
                NSLog(@"4---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"5---%@",NSThread.currentThread);
        });
        
        NSLog(@"6---%@",NSThread.currentThread);

    });
}

image.png

image.png

解释:1 6大家都理解,咱们重点研究4 3 2 5和4 5 2 3 1 6输出后,进入并发异步逻辑,2 4执行,然后3 5被阻塞,4先返回是因为任务4只需1s完成,这时候signal,信号量加一,3和5其中一个可以得到执行,因为是同一并发队列(优先级一样)异步,谁先执行无须在意,但只能执行其中的一个,因为只放出一条可执行线程,然后再过1秒,2完成signal,3 5剩下的一个任务得以执行。

3.并发队列异步 同步

代码语言:javascript复制
-(void)testSem{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_async(queue, ^{
        NSLog(@"1---%@",NSThread.currentThread);
        
        dispatch_async(queue, ^{
            [self netWork_task_requestTime:2 completionHandle:^{
                NSLog(@"2---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"3---%@",NSThread.currentThread);
            
        });
        
        dispatch_sync(queue, ^{
            [self netWork_task_requestTime:1 completionHandle:^{
                NSLog(@"4---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"5---%@",NSThread.currentThread);
        });
        
        NSLog(@"6---%@",NSThread.currentThread);

    });
}

image.png

相信经过上面的讲解,这里大家也很容易明白: 1输出后,2 4得以执行,但3被2阻塞,5 6被4阻塞,然后1秒后,4完成,5得以执行,因为是同步6再得以执行,再过1秒,2完成,3得以执行。

4.并发队列同步 异步

代码语言:javascript复制
-(void)testSem{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_async(queue, ^{
        NSLog(@"1---%@",NSThread.currentThread);
        
        dispatch_sync(queue, ^{
            [self netWork_task_requestTime:2 completionHandle:^{
                NSLog(@"2---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"3---%@",NSThread.currentThread);
            
        });
        
        dispatch_async(queue, ^{
            [self netWork_task_requestTime:1 completionHandle:^{
                NSLog(@"4---%@",NSThread.currentThread);
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            NSLog(@"5---%@",NSThread.currentThread);
        });
        
        NSLog(@"6---%@",NSThread.currentThread);

    });
}

image.png

我想这个结果你已经预料到了: 1执行之后,同步,所以等2秒后2完成,3得以执行,然后是异步,6执行,1秒后4完成,5执行。

总结:只要理解串行并发队列,同步异步,信号量机制,他们的关联使用也是小菜一碟,大家哪点不够明白就攻哪点,各个击破。

0 人点赞