iOS的三种多线程技术
#import "ViewController.h" @interface ViewController () { NSUInteger _tickets;//总票数 } @property (weak, nonatomic) IBOutlet UITextView *textView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.textView.text = @""; self.textView.layoutManager.allowsNonContiguousLayout = NO; //初始化总票数 _tickets = 20; //创建线程,并启动线程 //1.售票线程1 NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSellMethod) object:nil]; //设置线程的名字 [thread1 setName:@"售票线程-1"]; //启动线程 [thread1 start]; //2.售票线程2 NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSellMethod) object:nil]; //设置线程的名字 [thread2 setName:@"售票线程-2"]; //启动线程 [thread2 start]; } /** * 更新UI */ -(void)appendTextView:(NSString *)text { //1.获取textView中已有的内容 NSMutableString *string = [[NSMutableString alloc]initWithString:self.textView.text]; NSRange range = NSMakeRange(string.length, 1); //2.追加新的内容并显示 [string appendString:[NSString stringWithFormat:@"%@\n",text]]; [self.textView setText:string]; //3.滚动视图 [self.textView scrollRangeToVisible:range]; } /** * 线程执行的方法-售票 */ -(void)threadSellMethod { while (YES) { //判断是否有剩余票数 if (_tickets > 0) { //1.更新UI NSString *info = [NSString stringWithFormat:@"总票数:%ld,当前线程:%@",_tickets,[[NSThread currentThread]name]]; [self performSelectorOnMainThread:@selector(appendTextView:) withObject:info waitUntilDone:YES]; //2.售票 _tickets--; //3.模拟休息时间 if ([[[NSThread currentThread]name] isEqualToString:@"售票进程-1"]) { [NSThread sleepForTimeInterval:0.3f]; } else { [NSThread sleepForTimeInterval:0.2f]; } } else { //1.更新UI NSString *info = [NSString stringWithFormat:@"已无剩余票数,当前线程:%@",[[NSThread currentThread]name] ]; [self performSelectorOnMainThread:@selector(appendTextView:) withObject:info waitUntilDone:YES]; //2.退出线程 break; } } } @end
//NSThread的实例方法创建多线程
//1.售票线程1 NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSellMethod) object:nil]; //设置线程的名字 [thread1 setName:@"售票线程-1"]; //启动线程 [thread1 start];
//等效于: //NSThread的类方法创建多线程
[NSThread detachNewThreadSelector:@selector(threadSellMethod) toTarget:self withObject:@"售票线程-1"];
#import "ViewController.h" @interface ViewController () { NSUInteger _tickets;//总票数 } @property (weak, nonatomic) IBOutlet UITextView *textView; //@property(strong,nonatomic)NSLock *lock; //@property(strong,nonatomic)NSCondition *condition; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.textView.text = @""; self.textView.layoutManager.allowsNonContiguousLayout = NO; //初始化总票数 _tickets = 20; //创建线程锁 // self.lock = [[NSLock alloc]init]; // self.condition = [[NSCondition alloc]init]; //创建线程,并启动线程 //1.售票线程1 NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSellMethod) object:nil]; //设置线程的名字 [thread1 setName:@"售票线程-1"]; //启动线程 [thread1 start]; //2.售票线程2 NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSellMethod) object:nil]; //设置线程的名字 [thread2 setName:@"售票线程-2"]; //启动线程 [thread2 start]; } /** * 更新UI */ -(void)appendTextView:(NSString *)text { //1.获取textView中已有的内容 NSMutableString *string = [[NSMutableString alloc]initWithString:self.textView.text]; NSRange range = NSMakeRange(string.length, 1); //2.追加新的内容并显示 [string appendString:[NSString stringWithFormat:@"%@\n",text]]; [self.textView setText:string]; //3.滚动视图 [self.textView scrollRangeToVisible:range]; } /** * 线程执行的方法-售票 */ -(void)threadSellMethod { while (YES) { //判断是否有剩余票数 if (_tickets > 0) { /** * 加锁应该是在有竞争资源的地方 */ //访问竞争资源前进行加锁 // [self.lock lock]; // [self.condition lock]; /** * 需要同步的代码块放入synchronized块中 */ @synchronized(self) { @autoreleasepool { //1.更新UI NSString *info = [NSString stringWithFormat:@"总票数:%ld,当前线程:%@",_tickets,[[NSThread currentThread]name]]; [self performSelectorOnMainThread:@selector(appendTextView:) withObject:info waitUntilDone:YES]; //2.售票 _tickets--; } } //访问完竞争资源后进行解锁 // [self.condition unlock]; // [self.lock unlock]; //3.模拟休息时间 if ([[[NSThread currentThread]name] isEqualToString:@"售票进程-1"]) { [NSThread sleepForTimeInterval:0.3f]; } else { [NSThread sleepForTimeInterval:0.2f]; } } else { //1.更新UI NSString *info = [NSString stringWithFormat:@"已无剩余票数,当前线程:%@",[[NSThread currentThread]name] ]; [self performSelectorOnMainThread:@selector(appendTextView:) withObject:info waitUntilDone:YES]; //2.退出线程 break; } } } @end
运行结果如图:
现在再来看运行结果,发现上个案例中出现的问题已经解决了,每个只会出现一次。
再来看程序的代码部分,案例中使用了给出了三个解决同步安全问题的办法,代码中标出的蓝色部分是NSLock、NSCondition的用法,案例中使用的是@synchronized同步块。解决同步安全的逻辑思路“加锁”->"修改"->"解锁"。当当前线程正在使用竞争资源时,阻挡掉其他线程对竞争资源的访问。
在程序中还用到了内存管理的自动释放池。
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
在此案例中,不多做解释,直接代码搞起。
第一个案例通过NSInvocationOperation类进行实现
#import "ViewController.h" @interface ViewController () { NSUInteger _tickets; } @property (weak, nonatomic) IBOutlet UITextView *textView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化票数 _tickets = 30; //设置textView self.textView.text = @""; //创建NSOperation NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSaleMethod:) object:@"售票线程-1"]; NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSaleMethod:) object:@"售票线程-2"]; //创建NSOperationQueue队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //为operation1添加依赖,只有当operation2执行完毕时,operation1才能执行。 [operation1 addDependency:operation2]; //将operation加入到队列 [queue addOperation:operation1]; [queue addOperation:operation2]; } #pragma mark - 更新UI -(void)appendTextView:(NSString *)text { //1.先获取原先的内容 NSMutableString *str = [[NSMutableString alloc]initWithString:self.textView.text]; NSRange range = NSMakeRange(str.length, 1); //2.追加新的内容 [str appendString:[NSString stringWithFormat:@"%@\n",text]]; [self.textView setText:str]; //3.滚动textView [self.textView scrollRangeToVisible:range]; } #pragma mark - 线程调用的方法 -(void)operationSaleMethod:(NSString *)name { while (YES) { //判断剩余票数 if (_tickets > 0) { @synchronized(self) { NSString *info = [NSString stringWithFormat:@"总的票数:%ld,当前线程:%@",_tickets,name]; [[NSOperationQueue mainQueue]addOperationWithBlock:^{ [self appendTextView:info]; }]; //卖票 _tickets--; } if ([name isEqualToString:@"售票线程-1"]) { //线程休眠 [NSThread sleepForTimeInterval:0.3f]; } else { [NSThread sleepForTimeInterval:0.2f]; } } else { //更新UI NSString *info = [NSString stringWithFormat:@"已无剩余票数,当前线程:%@",name]; [[NSOperationQueue mainQueue]addOperationWithBlock:^{ [self appendTextView:info]; }]; break; } } } @end
案例2:通过NSBlockOperation进行实现
#import "ViewController.h" @interface ViewController () { NSInteger _tickets; } @property (weak, nonatomic) IBOutlet UITextView *textView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化票数 _tickets = 30; //设置textView self.textView.text = @""; //创建NSOperationQueue队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //设置线程的并行数量 [queue setMaxConcurrentOperationCount:2]; //在队列中添加block的operation [queue addOperationWithBlock:^{ [self operationSaleMethod:@"售票线程-1"]; }]; [queue addOperationWithBlock:^{ [self operationSaleMethod:@"售票线程-2"]; }]; NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ [self operationSaleMethod:@"售票线程-3"]; }]; //将线程添加到队列中去 [queue addOperation:operation]; } #pragma mark - 更新UI -(void)appendTextView:(NSString *)text { //1.先获取原先的内容 NSMutableString *str = [[NSMutableString alloc]initWithString:self.textView.text]; NSRange range = NSMakeRange(str.length, 1); //2.追加新的内容 [str appendString:[NSString stringWithFormat:@"%@\n",text]]; [self.textView setText:str]; //3.滚动textView [self.textView scrollRangeToVisible:range]; } #pragma mark - 线程调用的方法 -(void)operationSaleMethod:(NSString *)name { while (YES) { //判断剩余票数 if (_tickets > 0) { @synchronized(self) { NSString *info = [NSString stringWithFormat:@"总的票数:%ld,当前线程:%@",_tickets,name]; [[NSOperationQueue mainQueue]addOperationWithBlock:^{ [self appendTextView:info]; }]; //卖票 _tickets--; } if ([name isEqualToString:@"售票线程-1"]) { //线程休眠 [NSThread sleepForTimeInterval:0.3f]; } else { [NSThread sleepForTimeInterval:0.2f]; } } else { //更新UI NSString *info = [NSString stringWithFormat:@"已无剩余票数,当前线程:%@",name]; [[NSOperationQueue mainQueue]addOperationWithBlock:^{ [self appendTextView:info]; }]; break; } } } @end
以上两个案例的运行结果一致,如图:
如果希望当其中一个线程执行完毕之后,再去执行另外一个线程,可以通过依赖来实现。
//为operation1添加依赖,只有当operation2执行完毕时,operation1才能执行。 [operation1 addDependency:operation2];
累死啦!!
原文:http://www.cnblogs.com/xjf125/p/4857658.html