原文地址:关于iOS多线程,你看我就够了 感谢博主的劳动,下面是对于原文的一些解读和测试
#import
void*start(void*data){
NSLog(@"pthread:%@",[NSThreadcurrentThread]);
returnNULL;
}
-(void)run:(NSString*)string{
NSLog(@"NSThread: %@",string);
NSThread* thread = [NSThreadcurrentThread];
NSLog(@"%@",[threadisMainThread]?@"MainThread":@"NotMainThread");
[threadcancel];
}
-(void)doSomething:(NSString*)string{
NSLog(@"doSomthings");
}
... //方法主体
NSLog(@"start testing =========================");
//Pthreads
/*
POSIX threads,简称Pthreads,是线程的POSIX标准。在类UINX操作系统(UNIX、Linux、MacOS X等)中都使用Pthreads作为操作系统的线程。基于c语言实现,移植性很强。但是比较蛋疼的是需要手动处理线程的各种状态的转换,管理生命周期。
*/
pthread_tthread0;
pthread_create(&thread0,NULL,start,NULL);
pthread_kill(thread0,0);
//NSThread
/*
经过apple封装的面向对象的线程方法。但是它的生命周期也需要手动管理。
Question1:如何确定@selector(run:),run的参数类型呢?
Question2:体会void *start(void *data)和-(void)run:(NSString*)string这两种函数定义的区别~~
*/
/*
NSDateFormatter* formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"MMM dd,yyyy,HH:mm:ss"];
NSDate* date0 = [formatter dateFromString:@"12 12,1989,12:03:12"];
NSDate* date1 = [formatter dateFromString:@"12 12,1989,12:03:22"];
NSTimeInterval interval = [date0 timeIntervalSinceDate:date1];
*/
//挂起主线程,单位是秒
[NSThreadsleepForTimeInterval:1];
NSThread*thread1 = [[NSThreadalloc]initWithTarget:selfselector:@selector(run:)object:nil];
[thread1setName:@"Luke"];
[thread1start];
// [thread1 cancel];
//GCD:Grand Central Dispatch
/*
它是apple为多核的并行运算提出的解决方案,会自动合理的利用更多CPU内核,会自动管理线程的生命周期。
它也是用c语言的,但是因为使用了block,使用起来更方便。
主要有任务和队列两个概念。
任务:同步执行(sync)和异步执行(async)(Synchronized Asynchronous)
同步任务和异步任务的主要区别在于会不会阻塞当前线程,直到block执行完毕。sync会阻塞当前线程直到block执行完毕,线程才会继续执行。而async操作时,当前线程会继续执行。
队列:用于存放任务。一共有两种队列,串行队列和并行队列。
放到串行队列中的任务,GCD会按照FIFO(先进先出)依次取出一个一个执行。放到并行队列中的任务,GCD也会按照FIFO顺序取出,但是他取出后就会放入到一个新的线程中执行,因为取出时间几乎可以忽略,所以看起来并行队列中的任务是同时开始执行的。但是,GCD会根据系统资源控制并行的数量,所以如果任务很多时,并不能保证所有任务都同时执行。
*/
dispatch_queue_tqueue0 =dispatch_get_main_queue();//主线程队列,并行还是串行呢?????推测应该是并行
dispatch_queue_tqueue1 =dispatch_queue_create("threadsTest.dispatch.syncQueue1",NULL);//注意是""而非是@"",因为是c语言
dispatch_queue_tqueue2 =dispatch_queue_create("threadsTest.dispatch.syncQueue2",DISPATCH_QUEUE_SERIAL);//null和DISPATCH_QUEUE_SERIAL表示串行队列
dispatch_queue_tqueue3 =dispatch_queue_create("threadsTest.dispatch.asyncQueue3",DISPATCH_QUEUE_CONCURRENT);//并行队列
dispatch_queue_tqueue4 =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);//全局并行队列,并行任务一般都是加入到这个队列的。(应该是不会阻塞主线程的)
NSLog(@"before sync");
//dispatch_sync(queue0, ^{//引发问题的写法
dispatch_sync(queue1, ^{
//NSLog(@"sync %@",[NSThread currentThread]);
NSLog(@"done sync");
//return; //没有用,并不能结束这个串行线程
//这里的问题是,sync把主线程挂起后,自己没有结束,所以导致block和后面的内容都不会执行了。因为主线程队列中已经有了主线程,所以block会用主线程来执行,所以主线程挂起后,几乎什么事情都没有做了。而且GCD没有提供显式结束串行任务的api,所以导致无法退出挂起,所以串行任务应该加在非主线程队列中。
//加入非主线程队列中的逻辑是,挂起了非主线程队列中的其他线程,然后通过主线程执行block,执行完毕后唤醒非主线程队列中的其他线程
});//同步任务
NSLog(@"after sync");
NSLog(@"async 0");
dispatch_async(queue2, ^{//这里是正常的,往同步队列中放一个异步任务,会先建立一个线程执行,各走各的,使用当前异步线程执行block正常执行
NSLog(@"async 1");
//dispatch_sync(queue2, ^{//往同步队列中加入一个同步任务,因为是同步队列,已有有一个线程了,执行任务依托于原线程,挂起同步队列中其他所有的线程,也把异步线程挂起了,但是这里执行block需要用异步线程,因为线程挂起了,所以卡在这里了
dispatch_sync(queue0, ^{//放到主线程中,异步线程的任务正常执行
NSLog(@"async sync 2");
});
NSLog(@"async 3");
});
NSLog(@"async 4");
//上面这里例子核心要理解的是,执行任务是需要线程的,同步队列如果队列中已经有线程,应该就不会创建新的线程,所以一旦出现线程挂起,就会阻塞。主线程队列中自动就有一个线程,所以不会额外创建新的线程。新建线程队列的话,首先会先创建一个线程。
dispatch_sync(queue4, ^{
NSLog(@"tssss");//这里因为加入的是异步队列,所以会创建一个新的线程来执行任务,即便阻塞主线程,任务也能顺利结束。
});
NSLog(@"tasks end ");
//队列组,把所有队列放到一个队列组里,这样在所有任务执行完时,队列组可以通过一个方法来通知我们
dispatch_group_tgroup =dispatch_group_create();
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
NSLog(@"when nothings");
});
//其实看到这里就知道,对于GCD理解是需要注意的是,考虑清楚任务也就是block是由哪个线程来执行的(因为所有任务的执行都依托于线程),而且什么时候回创建新线程
//NSOperation和NSOperationQueue
/*
NSOperation只是一个抽象类(c or c++概念),不能封装任务,但是它的两个子类,NSInvocationOperation和NSBlockOperation可以封装任务.它相较于GCD的好处应该在于可以取消中途任务
*/
NSInvocationOperation* opration = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(doSomething:)object:nil];
// [opration start];
NSBlockOperation* blockOperation = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"block %@",[NSThreadcurrentThread]);
}];
for(inti =0; i <5; i++) {
[blockOperationaddExecutionBlock:^{//并发,会利用空闲线程(比如主线程)或者创建新线程执行。
NSLog(@"第%d次额外添加:%@",i,[NSThreadcurrentThread]);
if( i ==4){
[blockOperationcancel];
}
}];
}
[blockOperationstart];
NSOperationQueue* operationQueue = [NSOperationQueuemainQueue];
[operationQueueaddOperation:opration];//自动调用start
[operationQueuesetMaxConcurrentOperationCount:1];//这样就成同步队列了
//添加依赖
NSBlockOperation* b1 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"block 1");
[NSThreadsleepForTimeInterval:1.];
}];
NSBlockOperation* b2 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"block 2");
[NSThreadsleepForTimeInterval:2.];
}];
NSBlockOperation* b3 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"block 3");
[NSThreadsleepForTimeInterval:1.0];
}];
[b2addDependency:b1];
[b3addDependency:b2];
//[b1 start];
//[b2 start];
//[b3 start];//start下依赖状态也正常
NSOperationQueue* bqueue = [[NSOperationQueuealloc]init];
[bqueueaddOperations:@[b1,b2,b3]waitUntilFinished:NO];
//线程同步问题
//互斥锁,保证一次只有一个线程访问这个代码块
@synchronized(self) {
NSLog(@"aaa");
}
//同步执行,串行队列就可以搞定
//延迟执行
[selfperformSelector:@selector(run:)withObject:@"abc"afterDelay:3.];
//GCD有dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,10),dispatch_get_main_queue(), ^{
NSLog(@"主线程延迟10秒");
});
NSLog(@"dispatch_after是否会挂指定队列其他线程呢?答案是不会");
//NSTimer
[NSTimerscheduledTimerWithTimeInterval:10target:selfselector:@selector(run:)userInfo:@"efg"repeats:NO];