iOS开发之多线程的四种实现方式

2019-06-27  本文已影响0人  夜之海澜

多线程的优缺点:
优点:
1,简化了编程模型
2,更加的轻量级
3,提高了执行效率
4,提高了资源利用率

缺点:
1,增加了程序设计复杂性
2,占用内存空间
3,增大了CPU的调度开销

多线程的实现方法:

PThread: 是基于C框架的,在iOS中不常用;
创建方法及基础用法如下:

#pragma mark - PThread
- (void)clickPThread {
    NSLog(@"我在主线程中执行");
    //参数一:pthread指针 参数二:没什么用  设置成null 参数三:任务执行的方法  参数四:没什么用  设置成null
    pthread_t pthread;
    pthread_create(&pthread, NULL, run, NULL);
    
}

//C语言写法
void *run(void *data) {
    NSLog(@"我在子线程中执行");
    for (int i = 1; i < 10; i++) {
        NSLog(@"%d",i);
        sleep(1);
    }
    return NULL;
}
在控制台打印出来的信息可见: 1561449723563.jpg

其中打印日志中threadTest[26985:4948615] ,26985是进程的ID,而进程ID的后面4948615则是当前进程中的一个线程的线程ID,由此可知是在不同的线程中执行的。

NSThread: 苹果封装后的,并且是完全面向对象的,便于操作对象
有两种创建方式:

#pragma mark - NSThread
- (void)clickNSThread {
    NSLog(@"我在主线程中执行");
    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(runThread1) object:nil];
    [thread1 start];
}

- (void)runThread1 {
    NSLog(@"我在子线程中执行");
    for (int i = 1; i < 10; i++) {
        NSLog(@"%d",i);
        sleep(1);
    }
}
    [NSThread detachNewThreadSelector:@selector(runThread1) toTarget:self withObject:nil];
    [self performSelectorInBackground:@selector(runThread1) withObject:nil];

以上三种NSThread的创建方法中,二和三是没有创建相应的对象,无法操作其对象的属性,比如给NSThread的属性设置线程名字,可以更好的进行问题的定位。还可以设置优先级,如下图中,则thread2先执行,thread1后执行

- (void)clickNSThread {
    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(runThread1) object:nil];
    [thread1 setName:@"Name_Thread1"];
    [thread1 setThreadPriority:0.5];
    [thread1 start];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(runThread1) object:nil];
    [thread2 setName:@"Name_Thread2"];
    [thread2 setThreadPriority:0.5];
    [thread2 start];
}

- (void)runThread1 {
   NSLog(@"%@",[NSThread currentThread].name);//输出 Name_Thread1  Name_Thread2
    for (int i = 1; i < 10; i++) {
        NSLog(@"%d",i);
        sleep(1);
    }
}

GCD
任务分同步和异步,同步会阻塞线程,异步不会,dispatch_sync 线程同步、dispatch_async线程异步;
队列分串行和并行;
dispatch_get_global_queue是全局并行队列;
下面看简单的例子:
第一个:同步线程并行队列

    //线程同步,并行队列
    //因为是同步线程,执行起来则是顺序执行的
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"执行 task 1");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 1 ");
    });
    
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"执行 task 2");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 2 ");
    });
    
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"执行 task 3");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 3 ");
    });

这个例子中,无论执行多少次,打印顺序都是固定的,即


同步线程的并行执行的顺序

再来看第二个例子:异步线程并行队列

    //线程异步,并行队列,打印结果不可预期
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"执行 task 1");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 1 ");
    });

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"执行 task 2");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 2 ");
    });

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"执行 task 3");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 3 ");
    });

这个例子中,多次执行会发现,顺序并不是一成不变的,可能每次都不一样,无规律可循,即并行执行的特点。打印日志如下(此处我打印了三次)


线程异步的并行队列的执行顺序

再来看第三个例子:异步线程串行队列

//第二个参数传NULL,则创建出的是串行队列
//串行队列对应一个线程
dispatch_queue_t queue = dispatch_queue_create("com.gcd.test", NULL);
    dispatch_async(queue, ^{
        NSLog(@"执行 task 1");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 1 ");

    });
    
    dispatch_async(queue, ^{
        NSLog(@"执行 task 2");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 2 ");
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"执行 task 3");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 3 ");
        
    });

打印结果如下:


image.png

如上图可发现,是在同一进程同一线程中顺序执行的,即串行队列对应一个线程。

第四个例子:异步线程并行队列

 //手动创建的并行队列
    dispatch_queue_t queue = dispatch_queue_create("com.gcd.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"执行 task 1");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 1 ");
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"执行 task 2");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 2 ");
        
    });
    
    dispatch_async(queue, ^{
        NSLog(@"执行 task 3");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"end task 3 ");
        
    });

打印结果如下:


线程异步的并行队列的执行顺序

每次打印结果都会不同,且可以看出是在同一进程的不同线程中执行,即并行队列对应不同线程。

在iOS中是无法使用 dispatch_sync(dispatch_get_main_queue()
dispath向主队列加一个同步的block;
此时主队列在等待 dispatch_sync(dispatch_get_main_queue(),^(){block体});执行
dispatch_sync在等待主队列执行完毕。
所以在此过程中,我们最初调用的dispatch_sync函数一直得不到返回,main queue被阻塞,而我们的block又需要等待main queue来执行它。造成死锁。

NSOperation
NSOperation本身是一个基类,所以要使用其子类进行才能执行任务和线程。
两种使用方式:
1.系统封装好的NSInvocationOperation & NSBlockOperation;
这两个子类通过直接对象调start的方式是串行执行的,
若将其对象通过方法添加到队列中,则可以实现并行执行;
2.自定义类继承NSOperation

上一篇 下一篇

猜你喜欢

热点阅读