基础知识 - 多线程

基本概念

串行:多个任务依次执行,主线程算是比较特殊的一个线程
并行:多任务同时执行,执行效率特别高
并发:多任务轮流依次执行 a任务执行一部分,切到b任务执行一部分,给人的感觉像是多个任务同时执行,但是同一时间最终只有一个任务在被执行

进程和线程

进程:app启动,则开启一个进程,进程和应用是一一对应的关系,开启进程后,可以管理进程的状态变化等
线程:线程是操作系统进行运算调度的最小单位,

GCD

队列:同步队列,并发队列
DISPATCH_QUEUE_SERIAL 串行队列 主队列算是一种比较特殊的串行队列dispatch_get_main_queue
DISPATCH_QUEUE_CONCURRENT 并发队列,全局队列属于并发队列dispatch_get_global_queue,队列开启64个线程

任务
同步执行:dispatch_sync
1、同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
2、只能在当前线程中执行任务,不会创建新线程。
异步执行:dispatch_async
1、异步添加任务到指定的队列中,添加完成可以继续执行后面的代码。
2、可以在新的线程中执行任务,可能会创建新线程。

同步任务+主队列会因为队列等待导致的死锁
syncTaskInMainQueue被添加到主队列中,block1,block2也被添加到主队列中,又要同步添加到主队列的任务依次执行,所有block1,block2的执行依赖于syncTaskInMainQueue的执行,而syncTaskInMainQueue中block,block2不执行该方法也没法执行结束,这样就陷入了队列等待导致的死锁

- (void)syncTaskInMainQueue {

    NSLog(@"currentThread---%@",[NSThread currentThread]);
    NSLog(@"begin");

    dispatch_queue_t queue = dispatch_get_main_queue();
    //block1
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    //block2
    dispatch_sync(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"2---%@",[NSThread currentThread]);
    });

    NSLog(@"end");
}

线程组
dispatch_group
实现多网络请求并发
dispatch_group_enter 进入组
dispatch_group_leave 退出组
enter leave是成对出现的,如果不是成对,则会一直等待

信号量
dispatch_semaphore 信号量 信号量的值为0时,如果执行wait则会等待,发送sign信号,信号量的值会 1
dispatch_semaphore_create(0)
dispatch_semaphore_sign() 发送信号
dispatch_semaphore_wait() 等待

栅栏函数 - 多读单写
dispatch_barrier_async
dispatch_barrier_sync
在barrier之前的队列会先执行,接着执行barrier队列,最后再执行barrier以后的队列
任务3必须等到1、2都执行完之后才能执行4。

dispatch_queue_t conque1 = dispatch_queue_create("com.helloworld.djx1", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(conque1, ^{
        NSLog(@"1");
    });
    
    dispatch_async(conque1, ^{
        NSLog(@"2");
    });
    dispatch_barrier_async(conque1, ^{
        NSLog(@"3");
    });
    dispatch_async(conque1, ^{
        NSLog(@"4");
    });

多读单写 并发队列同一时间可以多个读者,由于barrier特性,只能存在一个写操作,写的同时,保证前面的所有都读完,然后进行写操作,写完成之后,在执行后续的操作

#import "WHObject.h"

@interface WHObject()

@property (nonatomic, strong) dispatch_queue_t dictQueue;//并发队列
@property (nonatomic, strong) NSMutableDictionary *dict;//可变字典

@end

@implementation WHObject

- (instancetype)init {
    if(self = [super init]) {
        _dictQueue = dispatch_queue_create("com.huangwenhong.queue", DISPATCH_QUEUE_CONCURRENT);
        _dict = [NSMutableDictionary dictionary];
    }
    return self;
}

- (void)huangwenhongmethod {
    self.target = [NSObject new];
}

- (id)valueForKey:(NSString *)key {
    id __block obj;
    dispatch_sync(_dictQueue, ^{//因为有数据 return,所以这里是同步调用
        obj = [self.dict valueForKey:key];
    });
    return obj;
}

- (void)setObject:(id)obj forKey:(id<NSCopying>)key {
    //重点:dispatch_barrier_async(),异步栅栏调用;
    //只有提交到并行队列才有意义
    dispatch_barrier_async(_dictQueue, ^{
        [self.dict setObject:obj forKey:key];
    });
}
@end

NSOperation/NSOperationQueue

NSOperation、NSOperationQueue 是 iOS 中一种多线程实现方式,实际上是基于 GCD 更高一层的封装,NSOperation 和 NSOperationQueue 分别对应 GCD 的任务和队列。面向对象,比 GCD 更简单易用
addDependency添加依赖关系
创建队列 添加任务到队列 执行队列
有点:
1、 控制开启的最大线程数
2、可以控制队列执行的状态 isFinished/isExecuting/isCanceled
3、可以添加依赖

NSThread

开启常驻线程过程:
1、创建一个线程
2、把线程添加runloop中
3、执行线程

@interface ViewController ()
@property (strong, nonatomic) NSThread *thread;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadStart) object:nil];
    [self.thread start];
    
}

- (void)threadStart{
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
    //往RunLoop里面添加Source\Timer\Observer 避免runloop里面没有事件执行退出
    [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];

    NSLog(@"%s ----end----", __func__);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}

// 子线程需要执行的任务
- (void)test
{
    NSLog(@"%s %@ 执行了test", __func__, [NSThread currentThread]);
}

posted @ 2022-07-25 17:27  qqcc1388  阅读(4)  评论(0)    收藏  举报