多线程

iOS多线程之NSThread,GCD,NSOperation

2017-03-28  本文已影响13人  charlotte2018
timg.jpeg

基本概念

进程: 一个具有一定独立功能的程序关于某个数据集合的一次运行活动。可以理解成一个运行中的应用程序。
线程: 程序执行流的最小单元,线程是进程中的一个实体。
同步: 只能在当前线程按先后顺序依次执行,不开启新线程。
异步: 可以在当前线程开启多个新线程执行,可不按顺序执行。
队列: 装载线程任务的队形结构。
并发: 线程执行可以同时一起进行执行。
串行: 线程执行只能依次逐一先后有序的执行。一个进程可以有多个线程,也可以有多个队列。

iOS多线程对比

  1. NSThread
    每个NSThread对象对应一个线程,真正最原始的线程。
    1)优点:NSThread 轻量级最低,相对简单。
    2)缺点:手动管理所有的线程活动,如生命周期、线程同步、睡眠等。

  2. NSOperation
    自带线程管理的抽象类。
    1)优点:自带线程周期管理,操作上可更注重自己逻辑。
    2)缺点:面向对象的抽象类,只能实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。

  3. GCD
    Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
    1)优点:最高效,避开并发陷阱。
    2)缺点:基于C实现。

  4. 选择小结
    1)简单而安全的选择NSOperation实现多线程即可。
    2)处理大量并发数据,又追求性能效率的选择GCD。
    3)NSThread用的少。

1. NSThread 创建方法一

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 创建线程
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector: @selector(run:) object:@"hehe"];
    //线程名字
    thread.name = @"wang";
    //开启线程
    [thread start];
    
}
- (void)run:(NSString*)str
{
    //d[2177:95263] -----run-----hehe--<NSThread: 0x60000026e440>{number = 3, name = wang}
     NSLog(@"-----run-----%@--%@", str, [NSThread currentThread]);
}

2. NSThread 其他创建方法

//方法二
[self performSelectorInBackground:@selector(run:) withObject:@"wang"];
//方法三

 [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"wang"];

3. 线程的状态

9F77DB76-6699-4DFE-BAFC-C9E6A8F5B534.png

4. 线程安全

//self 是锁对象
@synchronized(self) {
            //执行多线程操作
}

5. NSThread的其他api

// 获得主线程
+ (NSThread *)mainThread; 

// 是否为主线程
- (BOOL)isMainThread; 

// 是否为主线程
+ (BOOL)isMainThread; 

//获得当前线程
NSThread *current = [NSThread currentThread];

//线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;

//启动线程,进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态
- (void)start; 

//阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

//强制停止线程进入死亡状态一旦线程停止(死亡)了,就不能再次开启任务
+ (void)exit;

//线程间通信常用方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

6. GCD的任务和队列

/**
 * 异步函数 + 并发队列:可以同时开启多条线程
 */
- (void)asyncConcurrent
{
    // 1.创建一个并发队列
    // label : 相当于队列的名字
    // attr  : 并行 DISPATCH_QUEUE_CONCURRENT 串行 DISPATCH_QUEUE_SERIAL == NULL
//    dispatch_queue_t queue = dispatch_queue_create("wang", DISPATCH_QUEUE_CONCURRENT);
    
    // 1.获得全局的并发队列
    //#define DISPATCH_QUEUE_PRIORITY_HIGH 2
    //#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
    //#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
    //#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 2.将任务加入队列
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<2; i++) {
            NSLog(@"1-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<2; i++) {
            NSLog(@"2-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<2; i++) {
            NSLog(@"3-----%@", [NSThread currentThread]);
        }
    });
    
//    2017-03-28 17:10:40.609 07-GCD的基本使用[5361:272988] 3-----<NSThread: 0x60800026b9c0>{number = 5, name = (null)}
//    2017-03-28 17:10:40.609 07-GCD的基本使用[5361:272971] 1-----<NSThread: 0x60800026ba80>{number = 3, name = (null)}
//    2017-03-28 17:10:40.609 07-GCD的基本使用[5361:272973] 2-----<NSThread: 0x60800026be40>{number = 4, name = (null)}
//    2017-03-28 17:10:40.614 07-GCD的基本使用[5361:272988] 3-----<NSThread: 0x60800026b9c0>{number = 5, name = (null)}
//    2017-03-28 17:10:40.615 07-GCD的基本使用[5361:272971] 1-----<NSThread: 0x60800026ba80>{number = 3, name = (null)}
//    2017-03-28 17:10:40.615 07-GCD的基本使用[5361:272973] 2-----<NSThread: 0x60800026be40>{number = 4, name = (null)}
    
    
}

/**
 * 同步函数 + 并发队列:不会开启新的线程
 */
- (void)syncConcurrent
{
    // 1.获得全局的并发队列
    //#define DISPATCH_QUEUE_PRIORITY_HIGH 2
    //#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
    //#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
    //#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 2.将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    
//    2017-03-28 17:13:31.051 07-GCD的基本使用[5403:275128] 1-----<NSThread: 0x608000263940>{number = 1, name = main}
//    2017-03-28 17:13:31.053 07-GCD的基本使用[5403:275128] 2-----<NSThread: 0x608000263940>{number = 1, name = main}
//    2017-03-28 17:13:31.054 07-GCD的基本使用[5403:275128] 3-----<NSThread: 0x608000263940>{number = 1, name = main}
    
    
}


/**
 * 异步函数 + 串行队列:会开启新的线程,但是任务是串行的,执行完一个任务,再执行下一个任务
 */
- (void)asyncSerial
{
    // 1.创建串行队列
    //#define DISPATCH_QUEUE_SERIAL NULL
    dispatch_queue_t queue = dispatch_queue_create("wang", NULL);

    
    // 2.将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    
//    2017-03-28 17:16:02.187 07-GCD的基本使用[5495:278209] 1-----<NSThread: 0x608000262440>{number = 3, name = (null)}
//    2017-03-28 17:16:02.187 07-GCD的基本使用[5495:278209] 2-----<NSThread: 0x608000262440>{number = 3, name = (null)}
//    2017-03-28 17:16:02.188 07-GCD的基本使用[5495:278209] 3-----<NSThread: 0x608000262440>{number = 3, name = (null)}
}

/**
 * 同步函数 + 串行队列:不会开启新的线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务
 */
- (void)syncSerial
{
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("wang", DISPATCH_QUEUE_SERIAL);
    
    // 2.将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    
//    2017-03-28 17:17:25.275 07-GCD的基本使用[5527:279554] 1-----<NSThread: 0x6000000757c0>{number = 1, name = main}
//    2017-03-28 17:17:25.275 07-GCD的基本使用[5527:279554] 2-----<NSThread: 0x6000000757c0>{number = 1, name = main}
//    2017-03-28 17:17:25.275 07-GCD的基本使用[5527:279554] 3-----<NSThread: 0x6000000757c0>{number = 1, name = main}
    
}

/**
 * 异步函数 + 主队列:只在主线程中执行任务
 */
- (void)asyncMain
{
    // 1.获得主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 2.将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    
//    2017-03-28 17:20:38.682 07-GCD的基本使用[5591:282861] 1-----<NSThread: 0x600000065a40>{number = 1, name = main}
//    2017-03-28 17:20:38.683 07-GCD的基本使用[5591:282861] 2-----<NSThread: 0x600000065a40>{number = 1, name = main}
//    2017-03-28 17:20:38.683 07-GCD的基本使用[5591:282861] 3-----<NSThread: 0x600000065a40>{number = 1, name = main}
}
/**
 * 同步函数 + 主队列:
 */
- (void)syncMain
{
    NSLog(@"syncMain ----- begin");
    
    // 1.获得主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 2.将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    
    NSLog(@"syncMain ----- end");
}

7. GCD线程间的通信

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          //执行异步操作
        
        // 回到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            //刷新UI
        });
    });

8. GCD延时执行

/**
 * 延迟执行
 */
- (void)delay
{
    
    //方法1
    [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
    
    //方法2
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSLog(@"延迟执行");
    });
    
    //方法3
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
    
}

8. GCD只执行1次的代码dispatch_once

- (void)once
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"只执行1次的代码dispatch_once");
    });
    
}

9. GCD的dispatch_barrier栅栏

- (void)barrier
{
    dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });

    
    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });
 
//    2017-03-29 10:20:17.716 [1321:43448] ----1-----<NSThread: 0x608000264740>{number = 3, name = (null)}
//    2017-03-29 10:20:17.716 [1321:43722] ----2-----<NSThread: 0x60800007f7c0>{number = 4, name = (null)}
//    2017-03-29 10:20:17.716 [1321:43722] ----barrier-----<NSThread: 0x60800007f7c0>{number = 4, name = (null)}
//    2017-03-29 10:20:17.717 [1321:43722] ----3-----<NSThread: 0x60800007f7c0>{number = 4, name = (null)}
//    2017-03-29 10:20:17.717 [1321:43448] ----4-----<NSThread: 0x608000264740>{number = 3, name = (null)}

}

10. GCD的dispatch_apply

- (void)apply
{
  
    
    NSMutableArray *arr = [NSMutableArray array];
    
    for (int i=0; i<10; i++) {
        
        [arr addObject:@(i)];
    }
    
     dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(arr.count, queue1, ^(size_t index) {
        
        NSLog(@"%ld",index);
        
    });
    
//    2017-03-29 10:44:58.489 [1877:73243] 2
//    2017-03-29 10:44:58.489 [1877:73244] 1
//    2017-03-29 10:44:58.489 [1877:73213] 0
//    2017-03-29 10:44:58.489 [1877:73246] 3
//    2017-03-29 10:44:58.489 [1877:73243] 4
//    2017-03-29 10:44:58.489 [1877:73244] 5
//    2017-03-29 10:44:58.489 [1877:73213] 6
//    2017-03-29 10:44:58.489 [1877:73246] 7
//    2017-03-29 10:44:58.489 [1877:73243] 8
//    2017-03-29 10:44:58.490 [1877:73244] 9
    
}

11. GCD的dispatch_group

- (void)group
{
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 创建一个队列组
    dispatch_group_t group = dispatch_group_create();
    
    
    dispatch_group_async(group, queue, ^{
      
        NSLog(@"1");
        
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"2");
    });
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"完成了");
    });
    
//    2017-03-29 10:48:53.947 [1939:76156] 2
//    2017-03-29 10:48:53.947 [1939:76157] 1
//    2017-03-29 10:48:53.947 [1939:76157] 完成了
}

11. NSOperation的使用

- (void)blockOperation
{
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        // 在主线程
        NSLog(@"下载1------%@", [NSThread currentThread]);
    }];
    
    // 添加额外的任务(在子线程执行)
    [op addExecutionBlock:^{
        NSLog(@"下载2------%@", [NSThread currentThread]);
    }];

    [op addExecutionBlock:^{
        NSLog(@"下载3------%@", [NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
        NSLog(@"下载4------%@", [NSThread currentThread]);
    }];
    
    [op start];
}

- (void)invocationOperation
{
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

    [op start];
}

- (void)run
{
    NSLog(@"------%@", [NSThread currentThread]);
}

12. NSOperationQueue的使用

NSOperationQueue *queue = [[NSOperationQueue alloc] init];是可以开启线程的,串行和并行通过maxConcurrentOperationCount设置,为1的时候就是串行。[NSOperationQueue mainQueue]是在主线程执行任务。串行的

- (void)operationQueue1
{
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 创建操作(任务)
    // 创建NSInvocationOperation
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
    
    // 创建NSBlockOperation
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download3 --- %@", [NSThread currentThread]);
    }];
    
    [op3 addExecutionBlock:^{
        NSLog(@"download4 --- %@", [NSThread currentThread]);
    }];
    
    // 添加任务到队列中
    [queue addOperation:op1]; // [op1 start]
    [queue addOperation:op3]; // [op3 start]

}

- (void)operationQueue2
{
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  
    [queue addOperationWithBlock:^{
        NSLog(@"download1 --- %@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"download2 --- %@", [NSThread currentThread]);
    }];
}

- (void)opetationQueue3
{
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 设置最大并发操作数
    //    queue.maxConcurrentOperationCount = 2;
    queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
    
    // 添加操作
    [queue addOperationWithBlock:^{
        NSLog(@"download1 --- %@", [NSThread currentThread]);
        
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"download2 --- %@", [NSThread currentThread]);
        
    }];
   
}

- (void)suspend
{
    if (self.queue.isSuspended) {
        // 恢复队列,继续执行
        self.queue.suspended = NO;
    } else {
        // 暂停(挂起)队列,暂停执行
        self.queue.suspended = YES;
    }
    
    
    //取消任务
    [self.queue cancelAllOperations];
}

12. 自定义NSOperation的使用

@interface MyOperation : NSOperation

@end

@implementation MyOperation

/**
 * 需要执行的任务
 */
- (void)main
{
    NSLog(@"需要执行的任务");
}

@end

13. 任务之间添加依赖addDependency

- (void) addDependency{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download1----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download2----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download3----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"download4----%@", [NSThread  currentThread]);
        }
    }];
    NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download5----%@", [NSThread  currentThread]);
    }];
    op5.completionBlock = ^{
        NSLog(@"op5执行完毕---%@", [NSThread currentThread]);
    };
    
    // 设置依赖
    [op3 addDependency:op1];
    [op3 addDependency:op2];
    [op3 addDependency:op4];
    
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
    [queue addOperation:op4];
    [queue addOperation:op5];
}

13. 线程之间的通信

/**
 * 线程之间的通信
 */
- (void)test
{
    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        // 图片的网络路径
       NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
     
        
        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];
        
        // 生成图片
        UIImage *image = [UIImage imageWithData:data];
        
        // 回到主线程
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
        }];
    }];
}

上一篇下一篇

猜你喜欢

热点阅读