首页 > 代码库 > 多线程

多线程

  1. 主线程的生命周期和程序的生命周期一样.
  2. NSTimer不能在子线程上执行.
  3. 状态:创建->等待->运行->销毁->死亡.(另还有阻塞)

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] 释放资源

.