多线程(1)使用

进程和线程

  • 进程是系统资源分配和调度的一个独立单位,线程是进程的一部分,它是进程中用来执行任务的单位,一个进程(App)至少有一个线程;
  • 线程状态:新建态、就绪态、运行态、阻塞态、死亡态

NSThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[NSThread exit];//退出当前线程
[NSThread currentThread];//当前线程
[NSThread isMainThread];//是否在主线程
//类方法创建线程
[NSThread detachNewThreadWithBlock:^{}];
[NSThread detachNewThreadSelector:@selector(test) toTarget:self withObject:nil];
//创建线程
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];
[thread1 setName:@"线程名字"];
[thread1 start];//开始
[thread1 cancel];//取消并不退出
thread1.threadPriority = 1;//设置线程的优先级,范围为0-1的doule类型
//线程通信
[thread1 performSelector:@selector(test) onThread:thread1 withObject:@1 waitUntilDone:YES];

GCD

使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁

  • 基本使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//创建并行队列
dispatch_queue_t queue = dispatch_queue_create("ddddd", DISPATCH_QUEUE_CONCURRENT);
//创建串行队列
dispatch_queue_t queue1 = dispatch_queue_create("ddddd", DISPATCH_QUEUE_SERIAL);
//全局并行队列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//同步执行
dispatch_sync(queue, ^{
//任务
NSLog(@"%@",[NSThread currentThread]);
});
//异步执行
dispatch_async(queue, ^{
//任务
NSLog(@"%@",[NSThread currentThread]);
});
//主线程执行,不用能sync,会死锁
dispatch_async(mainQueue, ^{
//任务
NSLog(@"%@",[NSThread currentThread]);
});
  • 栅栏方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建并行队列
dispatch_queue_t queue = dispatch_queue_create("ddddd", DISPATCH_QUEUE_CONCURRENT);
//只有栅栏任务前面所有的任务执行完毕才会执行栅栏任务,栅栏任务执行完后才会执行栅栏后的任务
// 追加任务 1
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5]; // 模拟耗时操作
});
// 追加任务 barrier
dispatch_barrier_async(queue, ^{
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
});
// 追加任务 2
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5]; // 模拟耗时操作
});
  • 延时操作
1
2
3
4
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2.0 秒后异步追加任务代码到主队列,并开始执行
NSLog(@"after---%@",[NSThread currentThread]); // 打印当前线程
});
  • 只执行一次
1
2
3
4
5
6
7
8
9
//常用做单例
+ (instancetype)sharedInstance {
static Class *_instance;
static dispatch_once_t oneToken;
dispatch_once(&oneToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
  • 快速迭代
1
2
3
4
//快速迭代方法,执行该方法的是主线程,不能传入主队列否则会死锁
dispatch_apply(10, queue, ^(size_t t) {
NSLog(@"Task %@ %ld", [NSThread currentThread], t);
});
  • 调度组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//dispatch_group_enter 标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数+1
// dispatch_group_leave 标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数-1。
//当 group 中未执行完毕任务数为0的时候,才会使dispatch_group_wait解除阻塞,以及执行追加到dispatch_group_notify中的任务。
//全局并行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
//追加任务1
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
dispatch_group_leave(group);
});
//追加任务2
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
dispatch_group_leave(group);
});
//等待组任务完成,会阻塞当前线程,当任务组执行完毕时,才会解除阻塞当前线程
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
//都完成后调用此方法
dispatch_group_notify(group, queue, ^{
NSLog(@"All Task Complete");
});
  • 信号量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//dispatch_semaphore_create:创建一个Semaphore并初始化信号的总量
//dispatch_semaphore_signal:发送一个信号,让信号总量加1
//dispatch_semaphore_wait:可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); //最大并发数,当为1时,可以理解为线程锁
for (int i = 0; i < 10; i ++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//相当于加锁,
// 追加任务1
[NSThread sleepForTimeInterval:2];
NSLog(@"%d---%@ ",i,[NSThread currentThread]); // 打印当前线程
dispatch_semaphore_signal(semaphore);
});
}
  • 执行顺序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// 同步执行 + 并发队列 
// 在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
- (void)syncConcurrent {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"syncConcurrent---begin");
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
// 追加任务 1
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
});
dispatch_sync(queue, ^{
// 追加任务 2
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
});
dispatch_sync(queue, ^{
// 追加任务 3
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
});
NSLog(@"syncConcurrent---end");
}
// 打印顺序
//21:25 currentThread---<_NSMainThread: 0x6000001a8740>{number = 1, name = main}
//25:29 syncConcurrent---begin
//25:31 1---<_NSMainThread: 0x6000001a8740>{number = 1, name = main}
//25:33 2---<_NSMainThread: 0x6000001a8740>{number = 1, name = main}
//25:35 3---<_NSMainThread: 0x6000001a8740>{number = 1, name = main}
//25:35 syncConcurrent---end



// 异步执行 + 并发队列
// 可以开启多个线程,任务交替(同时)执行。
- (void)asyncConcurrent {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"asyncConcurrent---begin");
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue",DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
// 追加任务 1
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
});

dispatch_async(queue, ^{
// 追加任务 2
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
});

dispatch_async(queue, ^{
// 追加任务 3
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
});

NSLog(@"asyncConcurrent---end");
}
//33:17 currentThread---<_NSMainThread: 0x6000026dc880>{number = 1, name = main}
//33:17 asyncConcurrent---begin
//33:17 asyncConcurrent---end
//33:19 3---<NSThread: 0x60000269d440>{number = 3, name = (null)}
//33:19 1---<NSThread: 0x600002698b00>{number = 5, name = (null)}
//33:19 2---<NSThread: 0x6000026d5e40>{number = 7, name = (null)}



// 同步执行 + 串行队列
// 不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。
- (void)syncSerial {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"syncSerial---begin");
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
// 追加任务 1
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
});
dispatch_sync(queue, ^{
// 追加任务 2
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
});
dispatch_sync(queue, ^{
// 追加任务 3
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
});
NSLog(@"syncSerial---end");
}
//打印顺序
//22:05 currentThread---<_NSMainThread: 0x600000c6c080>{number = 1, name = main}
//22:05 syncSerial---begin
//22:07 1---<_NSMainThread: 0x600000c6c080>{number = 1, name = main}
//22:09 2---<_NSMainThread: 0x600000c6c080>{number = 1, name = main}
//22:11 3---<_NSMainThread: 0x600000c6c080>{number = 1, name = main}
//21:22 syncSerial---end


// 异步执行 + 串行队列
// 会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务
- (void)asyncSerial {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"asyncSerial---begin");

dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue, ^{
// 追加任务 1
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
});
dispatch_async(queue, ^{
// 追加任务 2
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
});
dispatch_async(queue, ^{
// 追加任务 3
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
});

NSLog(@"asyncSerial---end");
}
//38:48 currentThread---<_NSMainThread: 0x600003764140>{number = 1, name = main}
//38:48 asyncSerial---begin
//38:48 asyncSerial---end
//38:50 1---<NSThread: 0x60000373d540>{number = 5, name = (null)}
//38:52 2---<NSThread: 0x60000373d540>{number = 5, name = (null)}
//38:54 3---<NSThread: 0x60000373d540>{number = 5, name = (null)}


NSOperation和NSOperationQueue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//NSOperation、NSOperationQueue 是基于 GCD 更高一层的封装,完全面向对象。但是比 GCD 更简单易用、代码可读性也更高。
创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 2;//为1时串行队列,大于1为并行队列

使用 NSInvocationOperation 创建操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task2) object:nil];

使用 NSBlockOperation 创建操作
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 2; i++) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程
}
}];
[op3 addExecutionBlock:^{
for (int i = 0; i < 2; i++) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程
}
}];

//op1依赖op2,op2执行完才执行op1
[op1 addDependency:op2];

//添加所有操作到队列中
[queue addOperation:op1]; // [op1 start]
[queue addOperation:op2]; // [op2 start]
[queue addOperation:op3]; // [op3 start]