首页 > 代码库 > 多线程
多线程
- 主线程的生命周期和程序的生命周期一样.
- NSTimer不能在子线程上执行.
- 状态:创建->等待->运行->销毁->死亡.(另还有阻塞)
NSRunLoop:主循环,可以控制任何线程。
NSThread:自己管理状态,最复杂。
Cocoa NSOperation:
----------------------------------------------------------------------------------------------------
RootViewController.m
#import "RootViewController.h"@interface RootViewController (){ int count; int ticketNumber; NSLock *lock;}@end@implementation RootViewController- (void)viewDidLoad{ [super viewDidLoad]; // [self mA]; count = 100; ticketNumber = 0; lock = [[NSLock alloc]init]; NSThread *t1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil]; t1.name = @"窗口1"; [t1 start]; NSThread *t2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil]; t2.name = @"窗口2"; [t2 start]; NSThread *t3 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil]; t3.name = @"窗口3"; [t3 start]; }#pragma mark -NSThead的应用--(void)saleTicket{ while (1) { [lock lock]; if (count > 0) { count = 100 - ticketNumber; NSLog(@"%@卖出第%d张票,剩余%d张票",[NSThread currentThread].name,ticketNumber,count); ticketNumber++; } else { [lock unlock]; break; } [lock unlock]; }}#pragma make -1--(void)mA{ //oc中线程创建 /* //NSThread NSThread *t = [[NSThread alloc]initWithTarget:self selector:@selector(threadMethod) object:nil]; [t start]; */ // [self threadMethod]; //2// [NSThread detachNewThreadSelector:@selector(threadMethod) toTarget:self withObject:nil]; /* //3 NSOperation *operation = [[NSOperation alloc]init]; [operation setCompletionBlock:^{ for (int i = 0; i < 10; i++) { NSLog(@"新线程打印%d",i); } }]; [operation start]; */ /* //4 [self performSelectorInBackground:@selector(threadMethod) withObject:nil]; //回到主线程// [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>]; //在哪个线程上执行// [self performSelector:<#(SEL)#> onThread:<#(NSThread *)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>] */ //5.比较常用 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //可设置并发数,第一次并发多少个,下一次 queue.maxConcurrentOperationCount = 1; NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(threadMethod) object:nil]; //当CUP的资源不够时,可设置优先级,够的话,不影响优先级 [op setQueuePriority:NSOperationQueuePriorityVeryLow]; NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(threadMethod2) object:nil]; //当CUP的资源不够时,可设置优先级,够的话,不影响优先级 [op2 setQueuePriority:NSOperationQueuePriorityVeryHigh]; [queue addOperation:op]; [queue addOperation:op2]; //6.GCD [self mB]; }-(void)mB{ for (int i = 0; i < 10; i++) { NSLog(@"主线程打印%d",i); }}-(void)threadMethod{ for (int i = 0; i < 10; i++) { NSLog(@"新线程打印%d",i); }}-(void)threadMethod2{ for (int i = 0; i < 10; i++) { NSLog(@"新线程2打印%d",i); }}@end
---------------------------------------------------------------------------------------------
2.ImageOperation.h(自定义请求图片的线程Operation)参考资料:http://c.gzl.name/archives/137
/*自定义NSOperation*/@interface ImageOperation : NSOperation@property(nonatomic,assign)id target;@property(nonatomic,assign)SEL selector;@property(nonatomic,retain)NSString *imageURLString;-(id)initWithTarget:(id)target andAction:(SEL )selector andimageURLString:(NSString *)imageURLString;@end
ImageOperation.m (走完初始化init方法之后自动会走main方法)
#import "ImageOperation.h"@implementation ImageOperation-(id)initWithTarget:(id)target andAction:(SEL)selector andimageURLString:(NSString *)imageURLString{ if (self = [super init]) { self.target = target; self.selector = selector; self.imageURLString = imageURLString; } return self;}-(void)main{ if ([self isCancelled]) { return; } UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString:self.imageURLString]]];
[self.target performSelectorOnMainThread:self.selectorwithObject:image waitUntilDone:NO];//将image作参数传到self.selector方法中,image即self.target(作用绑定-initWithTarget:....)
if ([self isCancelled]) { return; }}@end
RootViewController.h
@interface RootViewController : UIViewController@property (weak, nonatomic) IBOutlet UIButton *GCDdownLoadBtn;@property (weak, nonatomic) IBOutlet UIButton *downloadBtn;@property (weak, nonatomic) IBOutlet UIImageView *headImageView;-(IBAction)downLoad:(id)sender;-(IBAction)GCDdownLoad:(id)sender;@end
RootViewController.m
#import "RootViewController.h"#import "ImageOperation.h"@implementation RootViewController- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self;}- (void)viewDidLoad{ [super viewDidLoad]; }-(IBAction)downLoad:(id)sender{ /* NSOperation *operation = [[NSOperation alloc]init]; [operation setCompletionBlock:^{ NSData *data = http://www.mamicode.com/[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic.6188.com/upload_6188s/flashAll/s800/20120827/1346029443Rd9sjm.jpg"]]; //ui要在主线程实现 UIImage *image = [UIImage imageWithData:data]; [self.headImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; } ]; [operation start]; */ /* //2没有写blcok就需要放到队列里才会异步 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; NSInvocationOperation *io = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(InvocationOperationDownload:) object:nil]; [queue addOperation:io]; */ //3 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; ImageOperation *imageOperation = [[ImageOperation alloc]initWithTarget:self andAction:@selector(refreshUI:) andimageURLString:@"http://pic.6188.com/upload_6188s/flashAll/s800/20120827/1346029443Rd9sjm.jpg"]; [queue addOperation:imageOperation]; }#pragma mark -3--(void)refreshUI:(UIImage *)image//因为self是image,所以这里的参数是UIImage{ [self.headImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];//给imageView设置image}#pragma mark -2--(void)InvocationOperationDownload:(NSInvocationOperation *)sender{ NSData *data = http://www.mamicode.com/[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic.6188.com/upload_6188s/flashAll/s800/20120827/1346029443Rd9sjm.jpg"]]; //ui要在主线程实现 UIImage *image = [UIImage imageWithData:data]; [self.headImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];}#pragma mark -4--(IBAction)GCDdownLoad:(id)sender{ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSData *data = http://www.mamicode.com/[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/w%3D1366%3Bcrop%3D0%2C0%2C1366%2C768/sign=334e29095143fbf2c52ca2208648f1e3/f603918fa0ec08faa42f1fa65bee3d6d55fbda80.jpg"]]; //ui要在主线程实现 UIImage *image = [UIImage imageWithData:data]; dispatch_async(dispatch_get_main_queue(), ^{ self.headImageView.image = image; }); });}@end
----------------------------------------------------------------------------------------------
3.NSRunLoop
RootViewController.m
#import "RootViewController.h"@interface RootViewController (){ int count;}@end@implementation RootViewController- (void)viewDidLoad{ [super viewDidLoad]; /*如何提高NSTimer的准确性*/ count = 0; NSOperationQueue *queue = [[NSOperationQueue alloc]init]; NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(threadMethod) object:nil]; [queue addOperation:op];}-(void)threadMethod{ @autoreleasepool { [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(print:) userInfo:nil repeats:YES]; } /*NSRunLoop是线程相关基础框架的一部分,一个runLoop就是一个事件处理机制的循环,它可以不停的调度任务以及处理输入事件 ,NSRunLoop可以保持一个线程处于活动状态,不会被销毁*/ [[NSRunLoop currentRunLoop]run];//主线程也有一个runloop,测试?计时器放在多线程下可以提高准确性,游戏需要 NSLog(@"runloop stop");}-(void)print:(NSTimer *)sender{ if (count == 10) { [sender invalidate]; } NSLog(@"hello world %d",count++); }@end
4.
CustomCell.h
@interface CustomCell : UITableViewCell@property(nonatomic,retain)UIImageView *downImageView;@property(nonatomic,retain)NSString *imageViewUrlStr;-(void)loadImageWithQueue:(NSOperationQueue *)queue;@end
Custom.m
#import "CustomCell.h"@implementation CustomCell- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { self.downImageView = [[[UIImageView alloc]initWithFrame:CGRectMake(10, 0, 100, 100)]autorelease]; [self.contentView addSubview:self.downImageView]; } return self;}-(void)setContentInCellWithModel:(NSString *)str{// self.downImageView.image}-(void)loadImageWithQueue:(NSOperationQueue *)queue//将加载图片的线程加入外面的队列中{ NSInvocationOperation *iop = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoad) object:nil]; [queue addOperation:iop]; [iop release];}-(void)downLoad{ UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.imageViewUrlStr]]]; [self.downImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];}-(void)down{// [NSURLConnection connectionWithRequest:<#(NSURLRequest *)#> delegate:self];}@end
RootViewController.h
@interface RootViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>{ NSMutableArray *dataSource; NSOperationQueue *queue;}@end
RootViewController.m
#import "RootViewController.h"#import "CustomCell.h"@implementation RootViewController- (void)viewDidLoad{ [super viewDidLoad]; dataSource = [[NSMutableArray alloc]initWithObjects:@"http://f.hiphotos.baidu.com/image/w%3D2048/sign=24dfaa86d2a20cf44690f9df42314a36/95eef01f3a292df59da38114be315c6034a8734a.jpg", @"http://a.hiphotos.baidu.com/image/w%3D2048/sign=5c4c05ef8fb1cb133e693b13e96c574e/f9dcd100baa1cd111a6f1c20bb12c8fcc2ce2dd0.jpg", @"http://b.hiphotos.baidu.com/image/w%3D2048/sign=0968c735347adab43dd01c43bfecb21c/503d269759ee3d6da48af3d641166d224f4ade5b.jpg", @"http://a.hiphotos.baidu.com/image/w%3D2048/sign=8214ba3fbb12c8fcb4f3f1cdc83b9345/ac4bd11373f08202aa30592049fbfbedab641b0b.jpg", @"http://c.hiphotos.baidu.com/image/w%3D2048/sign=4de426e7b68f8c54e3d3c22f0e112cf5/314e251f95cad1c845331c2e7d3e6709c93d512b.jpg", @"http://d.hiphotos.baidu.com/image/w%3D2048/sign=d2714dddc2cec3fd8b3ea075e2b0d53f/72f082025aafa40f20987eccaa64034f78f01940.jpg", @"http://c.hiphotos.baidu.com/image/w%3D2048/sign=3f69322892ef76c6d0d2fc2ba92efcfa/b03533fa828ba61e726728264334970a304e592a.jpg", @"http://b.hiphotos.baidu.com/image/w%3D2048/sign=6a784b289113b07ebdbd570838ef9023/e61190ef76c6a7ef5f91642ffffaaf51f3de6600.jpg", @"http://f.hiphotos.baidu.com/image/w%3D2048/sign=c8ff7f2271f082022d92963f7fc3faed/b21c8701a18b87d642cb301e050828381f30fd22.jpg", @"http://e.hiphotos.baidu.com/image/w%3D2048/sign=48e859cae4cd7b89e96c3d833b1c43a7/a8773912b31bb05164f6ea28347adab44bede0e4.jpg", nil]; // UITableView *tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320, 460) style:UITableViewStylePlain]; [self.view addSubview:tableView]; [tableView release]; tableView.rowHeight = 100; tableView.delegate = self; tableView.dataSource = self; // queue = [[NSOperationQueue alloc]init]; }#pragma mark - Table view data source- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return dataSource.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @"Cell"; CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[[CustomCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]autorelease]; } cell.imageViewUrlStr = [dataSource objectAtIndex:indexPath.row]; [cell loadImageWithQueue:queue]; return cell;}@end
--------------------------------------------------------------------------------------------------------------------------------
GCD中央回调,队列式结构:多核技术,性能最高
- 不可变对象通常是线程安全的。一旦你创建它们,您可以安全地通过这些对象和线程。另一方面,可变的对象通常不是线程安全的。使用可变的对象在线程的应用程序中,应用程序必须适当地同步。
1.线程问题:
- 更新同一数据时,容易出现数据竞争,原因是并发而导致数据同时更新,线程不安全。该情况适合用同步,通常同一个文件、单独一个表、对同一个文件写东西就可以考虑用同步。
- 同步的时候很容易出现死锁。
- 开启多个线程会消耗大量内存。
2.自定义线程:要管理内存
串行队列:Serial Diapatch Queue.等待现在执行处理结束
并行队列:Concurrent Dispatch Queue.不等待现在执行中处理结束
3.系统线程:不用管理内存
Main Diapatch Queue属于Serial Diapatch Queue类型
Global Diapatch Queue属于Concurrent Dispatch Queue类型,有4个优先级
Demo1---------------------------------------------------------自定义线程
//1自定义线程创建 dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);//第一个参数Serial Dispatch Queue的名称id.第二个参数NULL表示是Serial的,相反DISPATCH_QUEUE_CONCURRENT dispatch_release(mySerialDispatchQueue); dispatch_retain(mySerialDispatchQueue); //2自定义线程变更优先级方法 dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);
Demo2---------------------------------------------------------线程组,并发执行
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(@"one"); }); dispatch_group_async(group, queue, ^ { NSLog(@"two"); }); dispatch_group_async(group, queue, ^ { NSLog(@"three"); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^ { NSLog(@"done"); });
控制台输出结果:
2014-07-18 05:18:11.351 MutThreadDemo[2999:3507] two2014-07-18 05:18:11.351 MutThreadDemo[2999:3803] three2014-07-18 05:18:11.350 MutThreadDemo[2999:1303] one2014-07-18 05:18:11.398 MutThreadDemo[2999:60b] done
Demo3---------------------------------------------------------异步并行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^ { NSLog(@"one"); }); dispatch_async(queue, ^ { NSLog(@"two"); }); dispatch_async(queue, ^ { NSLog(@"three"); }); dispatch_async(queue, ^ { NSLog(@"four"); });
控制台结果:
2014-07-18 05:16:28.091 MutThreadDemo[2977:3507] two2014-07-18 05:16:28.091 MutThreadDemo[2977:3803] three2014-07-18 05:16:28.091 MutThreadDemo[2977:1303] one2014-07-18 05:16:28.091 MutThreadDemo[2977:3903] four
Demo4---------------------------------------------------------同步并行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_sync(queue, ^ { NSLog(@"hello1"); }); dispatch_sync(queue, ^ { NSLog(@"hello2"); }); dispatch_sync(queue, ^ { NSLog(@"hello3"); }); dispatch_sync(queue, ^ { NSLog(@"hello4"); }); dispatch_sync(queue, ^ { NSLog(@"hello5"); });
控制台输出结果:
2014-07-18 05:36:24.841 MutThreadDemo[3214:60b] hello12014-07-18 05:36:24.841 MutThreadDemo[3214:60b] hello22014-07-18 05:36:24.842 MutThreadDemo[3214:60b] hello32014-07-18 05:36:24.842 MutThreadDemo[3214:60b] hello42014-07-18 05:36:24.843 MutThreadDemo[3214:60b] hello5
Demo5---------------------------------------------------------并发处理数组类对象
NSArray *array = [NSArray arrayWithObjects:@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9", nil];//并发处理数组类对象 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^ { dispatch_apply([array count], queue, ^(size_t index) { NSLog(@"%zu: %@",index,[array objectAtIndex:index]); }); dispatch_async(dispatch_get_main_queue(), ^ { NSLog(@"done"); }); });
打印结果:
2014-07-18 06:00:08.645 MutThreadDemo[3456:3803] 1: 12014-07-18 06:00:08.646 MutThreadDemo[3456:3a03] 3: 32014-07-18 06:00:08.646 MutThreadDemo[3456:3903] 2: 22014-07-18 06:00:08.645 MutThreadDemo[3456:1303] 0: 02014-07-18 06:00:08.649 MutThreadDemo[3456:3a03] 5: 52014-07-18 06:00:08.649 MutThreadDemo[3456:3803] 4: 42014-07-18 06:00:08.649 MutThreadDemo[3456:3903] 6: 62014-07-18 06:00:08.650 MutThreadDemo[3456:1303] 7: 72014-07-18 06:00:08.653 MutThreadDemo[3456:3a03] 8: 82014-07-18 06:00:08.654 MutThreadDemo[3456:3803] 9: 92014-07-18 06:00:08.665 MutThreadDemo[3456:60b] done
Demo6---------------------------------------------------------控制线程队列
dispatch_suspend(queue);//挂起线程 dispatch_resume(queue);//重新恢复线程
Demo7----------------------------------------------------------并发串行队列
//1自定义线程创建 dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);//第一个参数Serial Dispatch Queue的名称id.第二个参数NULL表示是Serial的,相反DISPATCH_QUEUE_CONCURRENT dispatch_async(mySerialDispatchQueue, ^ { NSLog(@"one"); }); dispatch_async(mySerialDispatchQueue, ^ { NSLog(@"two"); }); dispatch_async(mySerialDispatchQueue, ^ { NSLog(@"three"); }); dispatch_async(mySerialDispatchQueue, ^ { NSLog(@"four"); });
控制台打印结果:
2014-07-18 19:39:55.973 MutThreadDemo[486:1303] one2014-07-18 19:39:55.973 MutThreadDemo[486:1303] two2014-07-18 19:39:55.974 MutThreadDemo[486:1303] three2014-07-18 19:39:55.974 MutThreadDemo[486:1303] four
Demo8---------------------------------------------------网络通信超时处理。因为GCD没有取消线程这个概念,只能用NSOperationQueue或者该处理方法。
//发送请求的同时调回主线程开始计时 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); //设置定时时间为15秒,允许延迟1秒 dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 15ull * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 1ull * NSEC_PER_SEC); dispatch_source_set_event_handler(timer, ^ { NSLog(@"网络请求失败,编写失败策略"); dispatch_source_cancel(timer); }); dispatch_source_set_cancel_handler(timer, ^ { NSLog(@"释放资源");// dispatch_release(timer); }); dispatch_resume(timer);//启动Dispatch Source定时
控制台输出:
2014-07-19 08:27:42.992 MutThreadDemo[960:60b] 网络请求失败,编写失败策略2014-07-19 08:27:42.993 MutThreadDemo[960:60b] 释放资源
.