iOS的三种多线程技术:


1. NSThread
1> 类方法 detachNewThreadSelector
直接启动线程,调用选择器方法

2> 成员方法 initWithTarget
需要使用start方法,才能启动实例化出来的线程

优点:简单
缺点:
1 控制线程的生命周期比较困难
2 控制并发线程数
3 先后顺序困难
例如:下载图片(后台线程) -> 滤镜美化(后台线程) -> 更新UI(主线程)

2. NSOperation
1> NSInvocationOperation
2> NSBlockOperation

定义完Operation之后,将操作添加到NSOperationQueue即可启动线程,执行任务

使用:
1> setMaxConcurrentOperationCount 可以控制同时并发的线程数量
2> addDependency 可以指定线程之间的依赖关系,从而达到控制线程执行顺序的目的

1 // Dependency依赖
2     // 提示:依赖关系可以多重依赖
3     // 注意:不要建立循环依赖
4     [op2 addDependency:op1];
5     [op3 addDependency:op2];


提示:
要更新UI,需要使用[NSOperationQueue mainQueue]addOperationWithBlock:
在主操作队列中更新界面


3. GCD
1) 全局global队列
方法:dispatch_get_global_queue(获取全局队列)
优先级:DISPATCH_QUEUE_PRIORITY_DEFAULT
所有添加到主队列中的任务都是并发执行的


2) 串行队列
方法:dispatch_queue_create(创建串行队列,串行队列不能够获取)
所有添加到串行队列中的任务都是顺序执行的

3) 主队列
主线程队列
方法:dispatch_get_main_queue(获取主队列)
所有添加到主队列中的任务都是在主线程中执行的

在gcd中,同步还是异步取决于任务执行所在的队列,更方法名没有关系

获取队列的方法:

全局队列(可能会开启多条线程)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

串行队列(只可能会开启一条线程)
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);

主队列
dispatch_get_main_queue();


多线程使用注意事项:
线程使用不是无节制的
iOS中的主线程的堆栈大小是1M
从第二个线程开始都是512KB
这些数值不能通过编译器开关或线程API函数更改
只有主线程有直接修改UI的能力

 1 static Ticket *SharedInstance;
 2 
 3 @implementation Ticket
 4 
 5 /**
 6  实现单例模型需要做三件事情
 7  
 8  1. 使用全局静态变量记录住第一个被实例化的对象
 9     static Ticket *SharedInstance
10  
11  2. 重写allocWithZone方法,并使用dispatch_once_t,从而保证在多线程情况下,
12     同样只能实例化一个对象副本
13  
14  3. 建立一个以shared开头的类方法实例化单例对象,便于其他类调用,同时不容易引起歧义
15     同样用dispatch_once_t确保只有一个副本被建立
16  
17  
18  关于被抢夺资源使用的注意事项
19  
20  在多线程应用中,所有被抢夺资源的属性需要设置为原子属性
21  系统会在多线程抢夺时,保证该属性有且仅有一个线程能够访问
22  
23  注意:使用atomic属性,会降低系统性能,在开发多线程应用时,尽量不要资源
24  另外,atomic属性,必须与@synchronized(同步锁)一起使用
25  
26  */
27 
28 // 使用内存地址实例化对象,所有实例化方法,最终都会调用此方法
29 // 要实例化出来唯一的对象,需要一个变量记录住第一个实例化出来的对象
30 + (id)allocWithZone:(NSZone *)zone
31 {
32     // 解决多线程中,同样只能实例化出一个对象副本
33     static dispatch_once_t onceToken;
34     dispatch_once(&onceToken, ^{
35         SharedInstance = [super allocWithZone:zone];
36     });
37 
38     return SharedInstance;
39 }
40 
41 // 建立一个单例对象,便于其他类调用
42 + (Ticket *)sharedTicket
43 {
44     static dispatch_once_t onceToken;
45     dispatch_once(&onceToken, ^{
46         SharedInstance = [[Ticket alloc]init];
47     });
48     
49     return SharedInstance;
50 }
51 
52 @end
  1 @property (weak, nonatomic) UITextView *textView;
  2 
  3 @property (strong, nonatomic) NSOperationQueue *queue;
  4 
  5 @end
  6 
  7 @implementation MainViewController
  8 
  9 #pragma mark 追加多行文本框内容
 10 - (void)appendContent:(NSString *)text
 11 {
 12     // 1. 取出textView中的当前文本内容
 13     NSMutableString *str = [NSMutableString stringWithString:self.textView.text];
 14     
 15     // 2. 将text追加至textView内容的末尾
 16     [str appendFormat:@"%@
", text];
 17     
 18     // 3. 使用追加后的文本,替换textView中的内容
 19     [self.textView setText:str];
 20     
 21     // 4. 将textView滚动至视图底部,保证能够及时看到新追加的内容
 22     NSRange range = NSMakeRange(str.length - 1, 1);
 23     [self.textView scrollRangeToVisible:range];
 24 }
 25 
 26 - (void)viewDidLoad
 27 {
 28     [super viewDidLoad];
 29 
 30     // 建立多行文本框
 31     UITextView *textView = [[UITextView alloc]initWithFrame:self.view.bounds];
 32     // 不能编辑
 33     [textView setEditable:NO];
 34     [self.view addSubview:textView];
 35     self.textView = textView;
 36 
 37     // 预设可以卖30张票
 38     [Ticket sharedTicket].tickets = 30;
 39     
 40     // 实例化操作队列
 41     self.queue = [[NSOperationQueue alloc]init];
 42     
 43     // 开始卖票
 44     [self operationSales];
 45 }
 46 #pragma mark - NSThread卖票
 47 - (void)threadSaleTicketWithName:(NSString *)name
 48 {
 49     // 使用NSThread时,线程调用的方法千万要使用@autoreleasepool
 50     @autoreleasepool {        
 51         while (YES) {
 52             @synchronized(self) {
 53                 if ([Ticket sharedTicket].tickets > 0) {
 54                     [Ticket sharedTicket].tickets--;
 55                     
 56                     NSString *str = [NSString stringWithFormat:@"剩余票数 %d 线程名称 %@", [Ticket sharedTicket].tickets, name];
 57                     
 58                     // 更新UI
 59                     [self performSelectorOnMainThread:@selector(appendContent:) withObject:str waitUntilDone:YES];
 60                 } else {
 61                     break;
 62                 }
 63             }
 64             
 65             // 模拟休息
 66             if ([name isEqualToString:@"thread-1"]) {
 67                 [NSThread sleepForTimeInterval:1.0f];
 68             } else {
 69                 [NSThread sleepForTimeInterval:0.1f];
 70             }
 71         }
 72     }
 73 }
 74 
 75 - (void)threadSales
 76 {
 77     [NSThread detachNewThreadSelector:@selector(threadSaleTicketWithName:) toTarget:self withObject:@"thread-1"];
 78     [NSThread detachNewThreadSelector:@selector(threadSaleTicketWithName:) toTarget:self withObject:@"thread-2"];
 79 }
 80 
 81 #pragma mark - NSOperation卖票
 82 - (void)operationSaleTicketWithName:(NSString *)name
 83 {
 84     while (YES) {
 85         // 同步锁synchronized要锁的范围,对被抢夺资源修改/读取的代码部分
 86         @synchronized(self) {
 87             // 判断是否还有票
 88             if ([Ticket sharedTicket].tickets > 0) {
 89                 [Ticket sharedTicket].tickets--;
 90                 
 91                 // 提示,涉及到被抢夺资源的内容定义方面的操作,千万不要跨线程去处理
 92                 NSString *str = [NSString stringWithFormat:@"剩余票数 %d 线程名称 %@", [Ticket sharedTicket].tickets, name];
 93                 
 94                 // 更新UI
 95                 [[NSOperationQueue mainQueue]addOperationWithBlock:^{
 96                     [self appendContent:str];
 97                 }];
 98             } else {
 99                 NSLog(@"卖票完成 %@ %@", name, [NSThread currentThread]);
100                 break;
101             }
102         }
103         // 模拟卖票休息
104         if ([name isEqualToString:@"op-1"]) {
105             [NSThread sleepForTimeInterval:0.6f];
106         } else {
107             [NSThread sleepForTimeInterval:0.4f];
108         }
109     }
110 }
111 
112 - (void)operationSales
113 {
114     // 提示,operation中没有群组任务完成通知功能
115     // 两个线程卖票
116     [self.queue setMaxConcurrentOperationCount:2];
117     
118     [self.queue addOperationWithBlock:^{
119         [self operationSaleTicketWithName:@"op-1"];
120     }];
121     [self.queue addOperationWithBlock:^{
122         [self operationSaleTicketWithName:@"op-2"];
123     }];
124     [self.queue addOperationWithBlock:^{
125         [self operationSaleTicketWithName:@"op-3"];
126     }];
127 }
128 
129 #pragma mark - GCD卖票
130 - (void)gcdSaleTicketWithName:(NSString *)name
131 {
132     while (YES) {
133         // 同步锁synchronized要锁的范围,对被抢夺资源修改/读取的代码部分
134         @synchronized(self) {
135             if ([Ticket sharedTicket].tickets > 0) {
136                 
137                 [Ticket sharedTicket].tickets--;
138                 
139                 // 提示内容
140                 NSString *str = [NSString stringWithFormat:@"剩余票数 %d, 线程名称 %@", [Ticket sharedTicket].tickets, name];
141                 
142                 // 更新界面
143                 dispatch_sync(dispatch_get_main_queue(), ^{
144                     [self appendContent:str];
145                 });
146             } else {
147                 break;
148             }
149         }
150         
151         // 模拟线程休眠
152         if ([name isEqualToString:@"gcd-1"]) {
153             [NSThread sleepForTimeInterval:1.0f];
154         } else {
155             [NSThread sleepForTimeInterval:0.2f];
156         }
157     }
158 }
159 
160 - (void)gcdSales
161 {
162     // 1) 创建全局队列
163     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
164     
165     // 2) 创建三个个异步任务分别卖票
166 //    dispatch_async(queue, ^{
167 //        [self gcdSaleTicketWithName:@"gcd-1"];
168 //    });
169 //    dispatch_async(queue, ^{
170 //        [self gcdSaleTicketWithName:@"gcd-2"];
171 //    });
172 //    dispatch_async(queue, ^{
173 //        [self gcdSaleTicketWithName:@"gcd-3"];
174 //    });
175     
176     // 3. GCD中可以将一组相关联的操作,定义到一个群组中
177     // 定义到群组中之后,当所有线程完成时,可以获得通知
178     // 1) 定义群组
179     dispatch_group_t group = dispatch_group_create();
180     
181     // 2) 定义群组的异步任务
182     dispatch_group_async(group, queue, ^{
183         [self gcdSaleTicketWithName:@"gcd-1"];
184     });
185     dispatch_group_async(group, queue, ^{
186         [self gcdSaleTicketWithName:@"gcd-2"];
187     });
188     
189     // 3) 群组任务完成通知
190     dispatch_group_notify(group, queue, ^{
191         NSLog(@"卖完了");
192     });
193 }
194 
195 @end
原文地址:https://www.cnblogs.com/yyh123/p/3356161.html