在iOS开发中有四种多线程的写法
1.Pthread
(这是一套通用的多线程API,但是现在几乎很少人用了);
2.NSThread
(可以直接操作的分线程,偶尔使用);
3.GCD
(苹果官方推出的替代NSThread的一种写法,利用设备的多核性能,经常被使用);
4.NSOperation
(面向对象的,GCD上的OC接口,经常被使用);
pthread的用法
1.创建线程
{ pthread_t thread ;
int error = pthread_create(&thread, NULL, task, NULL);
if (error != 0) {
NSLog(@"创建pthread类型的子线程失败");
}
}
/*
int pthread_create(pthread_t * thread,
pthread_attr_t * attr,
void * (*start_routine)(void *),
void * arg)
thread:返回创建的线程的ID
attr:线程属性,调度策略、优先级等都在这里设置,如果为NULL则表示用默认属性
start_routine:线程入口函数,可以返回一个void*类型的返回值,该返回值可由pthread_join()捕获
arg:传给start_routine的参数, 可以为NULL
*/
void *task(void *data){
for (int i=0; i<300000; i++) {
NSLog(@"当前运行次数%d",i);
}
return 0;
}
pthread_create();//创建一个线程
pthread_exit();//终止当前线程
pthread_cancel();//中断另外一个线程的运行
pthread_join();//阻塞当前的线程,直到另外一个线程运行结束
pthread_attr_init();//初始化线程的属性
pthread_attr_setdetachstate();//设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
pthread_attr_getdetachstate();//获取脱离状态的属性
pthread_attr_destroy();//删除线程的属性
pthread_kill();//向线程发送一个信号
NSThread用法
//先设计一个耗时操作
-(void)longtime task{
//在耗时操作里面打印当前线程对象
NSThread *currentThread = [NSThread currentThread];
NSLog(@"%@",currentThread);
for (int i=0; i<300000; i++) {
NSLog(@"当前运行次数%d",i);
}
}
//在程序中随意一个地方调起耗时操作(使用NSThread的方式调起)
//方式1:
[self performSelectorInBackground:@selector(longtimetask) withObject:nil];//iOS9以后,苹果公司觉得这个开线程的方法不安全,不推荐使用
//方式2:使用NSThread类方法创建多线程
[NSThread detachNewThreadSelector:@selector(longtimetask) toTarget:self withObject:nil];
//以上方式1和2 写法都是自动创建线程并且自动启动,但是无法设置线程的一些属性:例如线程的名字,线程的优先级
//方式3:使用NSThread创建线程对象,并给予对象的属性赋值
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(longtimetask) object:nil];
thread.name = @"子线程";//设置线程的名字
thread.threadPriority = 0.5;//设置线程的优先级(0.0 - 1.0,1.0最高级,最高级的子线程会被系统优先执行 )iOS8以后,使用了枚举类型的优先级qualityOfService;以下是从高到低排列
thread.qualityOfService = NSQualityOfServiceUserInteractive;//和视图相关的(优先级最高)
thread.qualityOfService = NSQualityOfServiceUserInitiated;//用户使用某个功能
thread.qualityOfService = NSQualityOfServiceUtility;//周期性操作,例如每五分钟循环请求网络数据;
thread.qualityOfService = NSQualityOfServiceBackground;//用户察觉不到的,做成功或者失败用户都没有感觉出来的事件
thread.qualityOfService = NSQualityOfServiceDefault;//这个优先级是最低的
[thread start];//启动线程
//如何退出子线程?
//在子线程的执行事件中找到自己想要的时机执行下面这句代码:
[NSThread exit];
//备注:不要在子线程中执行视图视图事件
//例如图片视图想要显示网络中的图片,下载图片的方法可以写在子线程中,但是显示图片的方法,就要回到主线程中操作
//NSThread 方式回到主线程的方法是:
[self performSelectorOnMainThread:@selector(refreshImageview:) withObject:downloadimage waitUntilDone:YES];
//waitUntilDone:(BOOL)wait 的意义是:YES表示回到主线程后,主线程所有的事件执行完毕才会再接着执行子线程上的剩余任务,NO表示主线程的事件和子线程的事件不相干扰,同步执行.
//如果需要重复启动一个线程,那么再启动线程之前需要先判断这个线程是否已经结束
if (self.thread.isFinished || self.thread.executing) {
self.thread = nil;
}
//线程锁(限制一个方法同一时间内只能被一个线程所运行)
1.声明一个线程锁属性;
NSLock *lock ;//然后对这个线程锁进行初始化
2.在被线程调用的方法内部加上加锁和解锁的代码
[self.lock lock];//加锁
[self.lock unlock];//解锁
3.GCD的使用
GCD的使用主要分为:a:主线程串行 b:主线程并行 c:子线程串行 d:子线程并行
a.主线程串行的情况
//使用GCD进行线程管理的必须创建任务队列
dispatch_queue_t queue1 = dispatch_queue_create("同步串行", DISPATCH_QUEUE_SERIAL);
//其中参数1.官方描述是一个添加到队列的字符串,可以为空,具体作用不知
//参数2.的作用是用来标记任务队列是串行还是并行.(DISPATCH_QUEUE_SERIAL-串行, DISPATCH_QUEUE_CONCURRENT-并行)
//任务队列创建好以后,需要加入到线程中,并同时添加任务
//dispatch_sync(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>) (主线程的开启方法)
//dispatch_async(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)(子线程的开启方法)
//下面代码是在主线程中添加一个串行任务队列执行两个任务
//创建执行任务的队列
dispatch_queue_t queue1 = dispatch_queue_create("同步串行", DISPATCH_QUEUE_SERIAL);//DISPATCH_QUEUE_CONCURRENT,DISPATCH_QUEUE_SERIAL
//开启线程
dispatch_sync(queue1, ^{
for (int i = 0; i<10; i++) {
NSLog(@"i=%d,当前线程:%@",i,[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
dispatch_sync(queue1, ^{
for (int j = 0; j<10; j++) {
NSLog(@"j=%d,当前线程:%@",j,[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
//运行起来会发现,系统会先执行完任务队列中的第一个任务,然后再执行第二个任务.
b.主线程并行的情况
//事实上主线程执行的代码并不会有并行的情况,如果任务全部放在主线程执行,系统会默认按照任务的先后添加顺序一次完成.
c.子线程串行的情况
//子线程的串行和主线程串行的效果很相似,区别在于,系统默认主线程的优先级在子线程之上
//子线程的意义在于:系统会把多个任务放在同一个子线程上依照任务的添加顺序呢依次完成
d.子线程并行的情况
//创建执行任务的队列
dispatch_queue_t queue4 = dispatch_queue_create("异步并行", DISPATCH_QUEUE_CONCURRENT);//DISPATCH_QUEUE_CONCURRENT,DISPATCH_QUEUE_SERIAL
//开启线程
dispatch_async(queue4, ^{
for (int i = 0; i<10; i++) {
NSLog(@"i=%d,当前线程:%@",i,[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
dispatch_async(queue4, ^{
for (int j = 0; j<10; j++) {
NSLog(@"j=%d,当前线程:%@",j,[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});