1. 概述
进程是系统对程序进行资源分配的单位。一个进程可以包含多个线程,而且进程一般都包含一个主线程,程序的代码都是在主线程上运行的。
一个app在手机上运行的时候,系统就会为期建立一个进程,其代码程序一般由主线程负责运行,之后开发者也可以在代码开启其他线程,利用多线程完成任务。
2. NSThread
NSThread是比较原生的线程编程方式,其包含有名字,优先级,cancel,executing,finished属性,直接看例子与注释吧:
//创建一个新线程
thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil];
[thread setName:@"logThread"];//设置线程的名字
thread.threadPriority = 0.1; //设置线程的优先级,从0.1~1.0,默认为0.5 //优先级越高获得的执行机会越多
[thread start];//启动线程进入就绪队列
for(int i=0; i<10; i++) {
NSLog(@"main Thread");
}
NSLog(@"正在运行的是:%@", [NSThread mainThread]);
if(thread.executing)//线程是否正在执行
NSLog(@"thread is run on cpu");
if(!thread.finished)//线程是否完成
[thread cancel];//将取消的属性设置为真
//线程的执行内容
-(void)run {
for(int i=0; i<100; i++) {
//如果当前执行的线程被设置成取消
if([[NSThread currentThread]isCancelled])
[NSThread exit];//退出当前线程的执行
NSLog(@"Sub Thread");
//正在执行的线程进入阻塞状态,暂停1s
[NSThread sleepForTimeInterval:1];
}
//在主线程中更新ui
[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:true];
}
3. GCD队列
这IOS为了简化多线程开发而提供的。队列就是先进先出,然后进进出出的是任务,任务就是你要让线程完成的一段代码,可以是一个函数,也一可以是一个代码块。然后队列就会自动的帮你执行任务代码。
每种队列都会维护一个线程池,线程池里有一个或者多个线程专门用来执行队列里面的任务。GCD的队列分为两种:
1)串行队列:线程池里只有一个线程,队列里面的任务按照先进先出的顺序,后一个任务必须等前一个任务完成后才能执行。
2)并发队列:线程池里维护多个线程,可以同时执行多个任务。队列里面的任务按线程数并发执行。
需要强调的是,这里的执行指的是线程进入系统的就绪队列,系统就绪队列里面的执行顺序跟系统的cpu分配策略有关,如多级反馈队列式。所以在并发队列里面的任务,后执行的任务可能会比先执行的任务先完成。然后不同队列之间的任务是并发的。即队列1在执行他的任务A的同时,队列2可能在执行他的任务B。
队列创建:
//自己创建一个名为“little.queue”的串行队列
dispatch_queue_t queue = dispatch_queue_create("little.queue", DISPATCH_QUEUE_SERIAL);
//获得系统提供的优先级为默认的全局并发队列
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//获得主线程相关的串行队列,即该队列线程池所维护的线程是主线程,你的程序主代码也当成一个任务在这里跑
queue = dispatch_get_main_queue();
异步提交:提交任务后立即返回,继续执行当前程序接下来的代码。
同步提交:提交任务后,必须等待任务在队列里被执行完毕后才返回继续执行当前程序接下来的代码。(感觉和单线程的顺序执行效果差不多)
//GCD队列
NSLog(@"1 %@", [NSThread currentThread]);
//异步提交主串队列, 由主线程完成
dispatch_async(dispatch_get_main_queue(), ^(void){
//for(int i=0; i<100; i++)
NSLog(@"2 %@", [NSThread currentThread]);
});
//同步提交到全局并发队列
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//for(int i=0; i<100; i++)
NSLog(@"4 %@", [NSThread currentThread]);
});
//异步提交,多次执行(多个线程并发执行同个代码块,并无顺序
dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t time){
NSLog(@"M%lu", time);
});
//同步提交,只执行一次,在主线程中执行
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"once");
});
执行完后,“2”是最后输出的,而且同步提交到主串队列会发生错误。我的理解是提交到主串队列的任务必须等待主程序代码执行完毕后才能执行,但是因为同步提交,主程序又必须等待任务完成后才能继续往下执行,由此造成了错误。
4. NSOperation
这个我感觉是GCD的缩减版。其只有一个FIFO的并发队列NSOperationQueue,可以并发多个NSOperation任务,NSOperation是对多线程任务一种面向对象封装。任务都是异步提交的。
你可以使用已经封装好的NSOpetation子类NSInvocationOperation,NSBlockOperation来直接用代码块创建多线程任务,你可以通过面向对象方法,新建一个继承NSOperation类并重写其main方法来使其完成特定的任务。下面是一个重写main方法的例子:
//
// PrintOperation.m
// ThreadTest
//
// Created by BlackApple on 2017/8/31.
// Copyright © 2017年 BlackApple. All rights reserved.
//
#import "PrintOperation.h"
@implementation PrintOperation
//override main函数
-(void)main {
NSLog(@"PrintOperation print");
}
@end
PrintOperation* printOperation = [[PrintOperation alloc]init];//创建任务
[[NSOperationQueue mainQueue] addOperation:printOperation];//提交任务到队列