今天我来详细介绍一下多线程的用法 包括线程整个的生命周期等等
1.0 NSThread 三种表现形式 详情看下面
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"打印当前线程%@",[NSThread currentThread]);
// 1. NSThread
// NSThread 线程有三种表现形式
// 1.1 创建对象 需要手动开启线程
NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(CommonSelector1) object:@"abc"];
[thread start];
// 1.2 从主线程中分离出一个线程 不需要手动开启
[NSThread detachNewThreadSelector:@selector(CommonSelector2) toTarget:self withObject:@"abc"];
// 1.3 从后台开辟一个线程
[self performSelectorInBackground:@selector(CommonSelector3) withObject:@"abc"];
}
-(void)CommonSelector1{
NSLog(@"打印当前线程----CommonSelector1 = %@",[NSThread currentThread]);
}
-(void)CommonSelector2{
NSLog(@"打印当前线程----CommonSelector2 = %@",[NSThread currentThread]);
}
-(void)CommonSelector3{
NSLog(@"打印当前线程----CommonSelector3 = %@",[NSThread currentThread]);
}
// 打印结果
2017-06-01 15:54:32.580 IOS-多线程2[10320:231085] 打印当前线程<NSThread: 0x600000065a80>{number = 1, name = main}
2017-06-01 15:54:32.581 IOS-多线程2[10320:231163] 打印当前线程----CommonSelector1 = <NSThread: 0x600000070d00>{number = 3, name = (null)}
2017-06-01 15:54:32.581 IOS-多线程2[10320:231164] 打印当前线程----CommonSelector2 = <NSThread: 0x600000070d40>{number = 4, name = (null)}
2017-06-01 15:54:32.583 IOS-多线程2[10320:231165] 打印当前线程----CommonSelector3 = <NSThread: 0x600000066f40>{number = 5, name = (null)}
2.0 GCD 这个好玩 这个复杂
2.1 异步async 下 dispatch_get_global_queue 与dispatch_get_main_queue 执行顺序
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"在主队列中执行任务时不会开启新的线程的");
});
// dispatch_get_global_queue 队列的优先级 DISPATCH_QUEUE_PRIORITY_HIGH 高中低
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
for (int i = 0; i<5; i++) {
NSLog(@"--5--%@",[NSThread currentThread]);
}
});
// dispatch_get_global_queue 队列的优先级 DISPATCH_QUEUE_PRIORITY_HIGH 高中低
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
for (int i = 0; i<5; i++) {
NSLog(@"--4--%@",[NSThread currentThread]);
}
});
// 输出结果
2017-06-04 12:17:10.381 NSOperation[2767:52779] --5--<NSThread: 0x608000076ac0>{number = 4, name = (null)}
2017-06-04 12:17:10.381 NSOperation[2767:52776] --4--<NSThread: 0x6080000765c0>{number = 3, name = (null)}
2017-06-04 12:17:20.249 NSOperation[2767:52779] --5--<NSThread: 0x608000076ac0>{number = 4, name = (null)}
2017-06-04 12:17:20.250 NSOperation[2767:52776] --4--<NSThread: 0x6080000765c0>{number = 3, name = (null)}
2017-06-04 12:17:22.807 NSOperation[2767:52776] --4--<NSThread: 0x6080000765c0>{number = 3, name = (null)}
2017-06-04 12:17:22.807 NSOperation[2767:52779] --5--<NSThread: 0x608000076ac0>{number = 4, name = (null)}
2017-06-04 12:17:27.115 NSOperation[2767:52717] 在主队列中执行任务时不会开启新的线程的
2.2 注意一种情况
// 这种情况下 只会输出 NSLog(@"1"); 然后程序crash 这是一个死锁
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"在主队列中执行任务时不会开启新的线程的");
});
NSLog(@"2");
3.0 GCD 的总结
1. dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
1.1> 串行队列不论是在sync 还是 async 中 执行任务 任务是依次进行的 但是在async 开启了新的线程
2. dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);
2.1> 并行队列在sync 中不回开启新的线程 在 async 中会开启新的线程
3. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3.1> 全局队列在sync 中不会开启新的线程 在 async 中会开启新的线程
4. 在async 中 如果 dispatch_get_main_queue 与 dispatch_get_global_queue 同时存在
4.1> 执行的先后顺序是 先执行 dispatch_get_global_queue 然后执行 dispatch_get_main_queue
5. 在dispatch_get_main_queue 添加sync 任务会造成死锁
在dispatch_get_main_queue 添加async 任务不会造成卡死 不会开启新的线程 任务是逐次完成的
线程的生命周期
/*
线程的生命周期
1. 首先我们会创建一个线程的对象 并将这个对象放到内存中
2. 然后我们开启线程,那么此时线程会被放倒内存池中,线程处于 准备被调用状态。等待CPU调度
3. 当CPU 调度该线程 处于线程调度状态 (这里提一个多线程同时调度)
当CPU 调度其他线程的时候 该线程处于 被调度状态
4. 线程阻塞:调度sleep/等待线程阻塞时
5. 线程的死亡:1.线程任务执行完成 自动死亡 2.线程异常/或者强制退出
// 关于线程这一块,不建议用互斥锁 占内存 容易造成死锁
互斥锁 是在一段时间内锁这线程 使其他线程不能访问 会占用大量的内存 不建议用
*/
NSOperation
我在工程中介绍了 NSOperation 的两种形式 还有一种自定义的没写,因为写了也没什么卵用 做项目根本 就不会用到