首页 > 代码库 > 多线程——NSThread、GCD、NSOperation

多线程——NSThread、GCD、NSOperation

1、前言:

一个应用程序就是一个进程,一个进程至少包含一个线程,程序启动会自动创建一个主线程,负责UI界面的现实和控件事件的监控。多线程可以更充分的利用系统CPU资源,一定程度上提升程序的性能。1个进程可以开启多条线程,每条线程可以并行(同时)执行不同的任务。在一个线程内可以包含多个事物(要干的活),在线程内依据先进先出的特性串行执行……

2、NSThread

- (void)viewDidLoad{    [super viewDidLoad];    NSLog(@"main thread is %@",[NSThread mainThread]);//打印主线程(UI线程)}-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    //新开辟一条子线程,启动子线程的时候调用downLoad方法,object是传递给子线程调用方法的参数    NSThread *thread=[[NSThread alloc] initWithTarget:self selector:@selector(downLoad:) object:@"luseike"];    //给子线程起一个名字    thread.name=@"thread one";    //开始子线程    [thread start];}-(void)downLoad:(NSString *)param{    //打印当前线程(子线程)及其名字和传递过来的参数    NSLog(@"begin downLoad--param is %@--current thread is %@ current name is %@",param,[NSThread currentThread],[NSThread currentThread].name);}

 打印结果如下:

2014-06-26 23:03:05.724 NSThread[50292:60b] main thread is <NSThread: 0x8c421c0>{name = (null), num = 1}

2014-06-26 23:03:06.567 NSThread[50292:3807] begin downLoad--param is luseike--current thread is <NSThread: 0xa33c350>{name = thread one, num = 2} current name is thread one

可以看到主线程的num=1,子线程的num=2,证明确实是新开辟了一条线程来执行downLoad操作。

还可以通过isMainThread判断是否是主线程,setThreadPriority:(double)p来设置子线程的优先级,优先级的取值范围在0.0~1.0之间,默认是0.5,值越大,优先级越高,被执行的几率越大

还有两种比较便捷的方式来创建子线程

1、[NSThread detachNewThreadSelector:@selector(downLoad:) toTarget:self withObject:@"luseike"];//  附加一个线程

2、[self performSelectorInBackground:@selector(downLoad:) withObject:@"haha"];  //在后台执行一个线程

这两种方式创建的子线程都不需要调用start方法,系统会自动执行对应的方法,都也都没有机会设置优先级和咸线程名等更详细的设置了,不过这个一般不重要

3、线程的状态

线程从生到死大致有下面几种状态:新建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、死亡(dead)

一个线程被创建之后会放到一个叫做可调度线程池内,等待被CPU调度,当该线程获得CPU的执行权时,就进入到running状态。running状态的线程如果调用sleep方法或者在等待同步锁,就会进入阻塞状态,进入阻塞状态的线程会重新被放到可调度线程池内,等待被重新调度。线程任务执行完毕,或者被强制退出,会进入dead状态,注意:进入dead状态的线程并没有被释放内存,只是不能用了而已,还存在内存中。

 

4、控制线程的状态

启动线程:之前介绍过,调用start方法

阻塞(暂停)线程:

  + (void)sleepUntilDate:(NSDate *)date;

  + (void)sleepForTimeInterval:(NSTimeInterval)ti;

强制停止线程:+(void)exit;

多线程的安全隐患:当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。解决的机制就是使用锁(互斥锁),让多条线程同步执行,这就是传说的线程同步技术。值得注意的是:锁定一份代码只用1把锁,用多把锁是没有意义的;线程同步的前提是多条线程抢占同一块资源

#import "ViewController.h"@interface ViewController ()@property(nonatomic,strong)NSThread *thread1;@property(nonatomic,strong)NSThread *thread2;@property(nonatomic,strong)NSThread *thread3;@property(nonatomic,assign)int totalCount;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    self.totalCount=100;    self.thread1=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];    self.thread2=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];    self.thread3=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];}-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    [self.thread1 start];    [self.thread2 start];    [self.thread3 start];}-(void)saleTicket{    int leftCount=self.totalCount;    while (leftCount>0) {        self.totalCount=leftCount--;        NSLog(@"%@ sale one ticket,left %d",[NSThread currentThread],leftCount);    }
}@end

 如上代码,模拟3个子线程同时访问公共资源totalCount,每次操作减一,多线程访问同一资源容易引起的数据安全问题已经说明了,打印部分结果如下

2014-06-26 23:51:33.639 NSThread[63065:360b] <NSThread: 0xa06dd50>{name = (null), num = 3} sale one ticket,left 99

2014-06-26 23:51:33.639 NSThread[63065:3707] <NSThread: 0xa0706e0>{name = (null), num = 2} sale one ticket,left 99

2014-06-26 23:51:33.639 NSThread[63065:3f03] <NSThread: 0xa06ddf0>{name = (null), num = 4} sale one ticket,left 99

2014-06-26 23:51:33.641 NSThread[63065:3707] <NSThread: 0xa0706e0>{name = (null), num = 2} sale one ticket,left 98

2014-06-26 23:51:33.641 NSThread[63065:3f03] <NSThread: 0xa06ddf0>{name = (null), num = 4} sale one ticket,left 98

2014-06-26 23:51:33.642 NSThread[63065:3707] <NSThread: 0xa0706e0>{name = (null), num = 2} sale one ticket,left 97

2014-06-26 23:51:33.641 NSThread[63065:360b] <NSThread: 0xa06dd50>{name = (null), num = 3} sale one ticket,left 98

2014-06-26 23:51:33.642 NSThread[63065:3f03] <NSThread: 0xa06ddf0>{name = (null), num = 4} sale one ticket,left 97

可以看到三个子线程都操作了totalCount变量,每次操作之后的值却没有变化……

互斥锁的使用格式:

@synchronized(锁对象) { // 需要锁定的代码  }

-(void)saleTicket{    while (1) {        @synchronized(self) { // 加锁(只能用一把锁)            // 1.先检查票数            int count = self.totalCount;            if (count > 0) {                self.totalCount = count - 1;                                NSThread *current = [NSThread currentThread];                NSLog(@"%@ sale one ticket, left %d tickets", current, self.totalCount);            } else {                [NSThread exit];            }        }     }}

 打印结果就可以正常显示了……

很晚了,有时间在写写GCD和NSOperation