JFC

IOS线程的一些总结

 

主线程的作用 (在主线程中才能设置)

显示/刷新UI界面

处理UI事件(比如点击事件、滚动事件、拖拽事件);

 

主线程的使用注意

别将比较耗时的操作放到主线程中。

耗时操作会卡住主线程。影响体验。

[NSThread currentThread]获得当前线程。

打印线程。num属性显示有多少条线程。

 

将耗时操作放在子线程中(后台线程,非主线程);

多线程好处在哪?

在用户点击按钮那一刻就有反应

能同时处理耗时操作和用UI控件的事件。

多线程技术:

1,pthread    一套通用的多线程API(几乎不用)

适用于Unix\Linux\Windows等系统

跨平台\可移植

使用难度大。

需要程序员来管理线程的生命周期。

创建一个线程用

 

pthread_create(&pthread_t,NULL,(void *)(*)(void *),NULL);即可

 

2,NSThread  使用OC,(程序员管理)

使用更加面向对象

简单易用,可直接操作线程对象

创建一个线程用 [NSThread alloc] init……

[self start] 开启;

selector(mainThread) 返回主线程;

selector(isMainThread) 是否是主线程;

selector (currentThread); 判断当前线程;

可以设置线程优先级, 

优先级越高,CUP的占有率越高。

线程有name属性,可以设置名字。

创建线程第2种方式:

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

分离一条线程,没有返回值。

 创建线程第3种方式。

[self performSelectorInBackground:@selector(run:) withObject:@"abc参数"];

 

 每一个时刻只有一个线程在执行。

[thread start]后进入一个可调度线程池(有机会被调度。状态为就绪或运行);

          start

new  ----》 就绪  -----》运行

                             《------

调用了sleep方法或等待同步锁 后就进入  阻塞状态(清出线程池)  条件满足后又回到调度池。

调用stop 线程进入的是dead 死亡状态。再也没有了。

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

+(void) sleepForTimeInterval:(NSTimeInterval)ti; 

 

线程运行完之后就会死亡, 不能能再次调用。

[thread exit]线程退出。 

 

3,GCD   C

旨在替代NSThread等线程技术

充分利用设备的多核。(自动)

不用管理线程。

GCD有2个核心概念

任务:执行什么样的操作。

队列:用来存放任务。

GCD的使用就2个步骤。

定制任务

确认想做的事情。

将任务添加到队列中

GCD会自动将队列中的任务取出,放到对应的线程中执行。

任务取出遵循队列的FIFO原则,先进先出。后进后出

调用libdispach库才行

都是懿dispatch开头。

 

1,用同步的方式来执行任务。(有顺序执行)

dispatch_sync(queue,block);同步执行

queue:队列

block:任务

2,用异步的方式执行任务(在另一条线程中执行)

dispatch_async(queue,block);

GCD队列分2大类;

并发队列;

可以让任务同时执行。

串行队列

用函数给队列赋值任务;

队列分为并行和串行。

函数分为同步和异步。

异步函数加并行队列  == 开一条子线程。

同步:在当前线程中执行任务,不具备开启新线程能力

异步:在新的线程中执行任务,具备开启新线程的能力。

 

并发和串行决定了任务的执行方式。

 

并发:多个任务并发执行。  调用dispatch_queue_t queue = dispatch_get_global_queue(优先级,随意值);

添加任务到队列中,执行任务。

 

 

串行:一个任务执行完毕后,再执行下一个任务。

serial 英文,连续,串行的意思。。

dispatch_queue_t queue = dispatch_queue_create("com.itheima,queue",队列的类型);

队列名称在调试的时候可以看的到代码在哪个队列里面执行。

 

调用async函数会开启一个线程,但是如果函数的队列是串行的就不会开更多了。每加一个并行队列开启线程数会加1.

调用sync函数不会开线程。并行和串行队列都一样

 MRC里面释放用dispatch_release(queue);

ARC里面不能用,会自动释放。

 

即使在ARC中

凡是函数名中带有create\copy\new\retain等字眼返回值的,都需要在不使用这个数据的时候进行release(有的话都写一下,报错就不写了)

GCD数据类型则不用,release。  

CF(Core foundation)的数据类型在ARC环境下还是得需要再做release;

系统自带的用get ,自己创的用create 。(苹果规范);

主线程队列是不会开新线程的。

 别在主线程中用同步函数添加主队列,会形成相互等待,死锁。

用异步函数可以(异步可以延缓执行,同步要马上执行)。

同步会在当前进程中执行,会停下来。异步会自己开一个线程。与当前线程并发执行,(只要队列不是主队列)

 

iOS常见的延时执行有2种方式;

1,[self performSelector:@selector(run)  withObject:nil afterDelay:2.0];

2秒之后调用run方法;

2,GCD方式

dispatch_after();//有个队列参数,表示多少秒后在哪个线程中执行。

     //1.声明在哪个队列

     dispatch_queue_t queue = dispatch_get_main_queue();

    // 2.计算任务执行的时间

    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));

     // 3.会在when这个时间点, 执行queue中的任务

    dispatch_after(when, queue, ^{        //会另外声明一个队列。

        NSLog(@"----run----%@", [NSThread currentThread]);

    });

需要整个程序执行过程中只能打印一次时。

static dispatch_once_t onceToken;

可以用 dispatch_once(&onceToken,^{

    NSLog(@"--------touchesBegin");

});

 

队列组,:

有这么一种需求。

等2个线程都执行完之后再到主线程中执行操作。

就可以用队列组把2个线程封装。执行队列组。   

 

创建group//比串行执行要快很多。。。

    dispatch_group_t group = dispatch_group_create();

 创建队列

   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

 把任务和队列放到异步组函数中

  */

    dispatch_group_async(group, queue, ^{

        for (int i=0; i<100; i++) {

            NSLog(@"执行线程一:%d",i);

        }

    });

    

    dispatch_group_async(group, queue, ^{

        for (int i=0; i<100; i++) {

            NSLog(@"执行线程二:%d",i);

        }

    });

//线程组执行完成后执行:(重点,没有它,要组也没啥用了)

 dispatch_group_notify(group, queue, ^{

        NSLog(@"线程组执行完成");

    });

 //下面是重复执行:10代表重复执行次数。中间是执行队列。index是第几次执行;(注意执行是并发(这是与for循环的区别));

    dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {

        //index表示是第几次执行

        NSLog(@"执行第%zu次",index);

        

    });

 

栅栏barrier ,用来将线程分开,执行完上面的线程到执行它再到执行后面的线程;(有队列queue关键字,所以就是把queue队列的隔开,其它队列可不行,中间执行)

dispatch_barrier_async(queue, ^{

        NSLog(@"barrier");

    });

 

 

 

4,NSOperation  OC

基于GCD

比GCD多了一些简单实用的功能

使用更加面向对带的用get ,自己创的用create 。(苹果规范);

, 配合使用NSOperation NSOperationQueue也能实现多线程编程

,NSOperation和NSOperationQueue 实现多线程的具体步骤

先将需要执行的操作封装到一个NSOperation 对象中。

然后将NSOperation对象添加到NSOperationQueue中

系统会自动将NSOperationQueue中的NSOperation取出来

将取出的NSOperation封装的操作放到一条新线程中执行。

NSOperation是一个抽象类,并不具备封装操作的能力,必须使用它的子类。

 

使用NSOperation子类的方式有3种。

NSInvocationOperation

NSBlockOperation

自定义的子类继承NSOperation,实现内部相应的方法。

 

NSInvocationOperation  

创建操作对象,封装要执行的任务。

NSInvocationOperation * operation = [  alloc]  initwithTarget……   任务是方法;

可以[operation start]调用,但是这样是会在当前线程中调用,并无啥用,还是得放到方法中去;

NSBlockOperation

使用类方法来声明

NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock^{   }];   任务是block ,NSBlockOperation 是block的封装

也可以  直接用start 调用,但也无啥用。

有方法:  [operation addExecutionBlock:^{

     NSLog(@"%@",[NSThread currentThread]);

}];

只要operation封装的任务大于1,就会异步执行。

调用了addExecutionBlock 的话 operation的任务就有多个。   用start是会多线程执行的。

 

-(void) invocationOperation

{

        

}

NSOperatinQueue * queue =[ [NSOperationQueue alloc] init];

[queue addOperation:operation1];

[queue addOperation:operation2];//这样直接就会是异步执行。   (并发有着不确定性。但是概率是会有的)

 

队列可以设置 最大并发数,  queue.maxConcurrentOperationCount = 1;  表示在这个队列中最多同时执行的并发任务数为1;

(不要设置太多,不然可能会卡, 2-3就好,5以内,不然UI会卡);

- (void) cancelAllOperations; 队列的全部线程都停掉

也可以调用NSOperation 的-(void)cancel 方法取消单个操作。

-(void)setSuspended:(BOOL)b;//YES 代表暂停队列

 

//(一个比较好的地方是 : cancel代表取消的意思,suspended,表示已经挂起,这些英文记住了用来命名挺好的,看看别人的过去时都是加ed的,就是这么强,所以语法不好的话,多关注ios的命名规则时很好的);

 

当下载时,同时开启多条子线程,当用户操作UI时会发生卡顿现象,那么我们就可以在用户滚动时挂起队列。不操作时就继续队列/

下载时同时开启多条线程下载会比较快。

 

有个有趣的地方是 NSOperation 居然也有一个队列优先级, 我了个去, 不愧是GCD的封装啊 ,就是那么强大。

 还可以设置依赖。来保证执行的顺序;

[operationB addDependency: operationA]; B依赖A  那么B只能在A之后执行。(灵活应用可以做很多事情。)

A-》B    B -》C   C—》A 

小心相互依赖问题。

 

 

可以在不同的queue的NSOperation之间创建依赖关系。但是不能相互依赖。

 操作的监听。

operation.completionBlock = ^{

   //下载完图片后想做的事情。

};

 自定义Operation(继承自Operation)

       要在operation里面实现  -(void)main{}方法

 

 

多线程安全隐患:1,一块资源可能会被多个线程共享,也就是多个线程可能会访问同一个资源

    比如说多个线程访问同一个对象、同一个变量、同一个文件。

使用线程锁来解决,同一时间只能有一个线程访问。

 

posted on 2016-01-07 18:55  JFC  阅读(166)  评论(0编辑  收藏  举报

导航