1,从操作系统的角度看什么是线程,线程和进程的区别。
对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。
有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。
概括一下:
1、进程是一段正在执行的程序,是资源分配的基本单元,而线程是CPU调度的基本单元。
2、进程间相互独立进程,进程之间不能共享资源,一个进程至少有一个线程,同一进程的各线程共享整个进程的资源(寄存器、堆栈、上下文)。
3、线程的创建和切换开销比进程小。
那也就是说,因为线程是共享进程的资源,如果你在一个线程里处理资源,只需要做好线程同步就好了。比如一个进程里的两个线程同时处理一个可变数组,两个线程是可以直接操作这个数组的,都可以添加,修改和删除元素;并且进程的调度是由操作系统来进行的,先后是无法保证的。比如一个线程要修改数组中第三个元素,另个线程要插入元素到第二个元素后面,代码先后是无法保证线程先后调用顺序的,比如可以使用串行队列来解决以上问题。
在 iOS 中其实目前有 4
套多线程方案,他们分别是:
- Pthreads
- NSThread
- GCD
- NSOperation & NSOperationQueue
更需要手动处理线程的各个状态的转换即管理生命周期,比如,这段代码虽然创建了一个线程,但并没有销毁。基本上没人用它了。
#import
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
pthread_t thread;
//创建一个线程并自动执行
pthread_create(&thread, NULL, start, NULL);
}
void *start(void *data) {
NSLog(@"%@", [NSThread currentThread]);
return NULL;
}
NSThread
先创建线程类,再启动
OBJECTIVE-C
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
SWIFT
//创建
let thread = NSThread(target: self, selector: "run:", object: nil)
//启动
thread.start()
创建并自动启动:
OBJECTIVE-C:
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
SWIFT
NSThread.detachNewThreadSelector("run:", toTarget: self, withObject: nil)
Grand Central Dispatch
在 GCD
中,加入了两个非常重要的概念: 任务 和 队列。
任务:即操作,你想要干什么,说白了就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。任务有两种执行方式: 同步执行 和 异步执行
如果是 同步(sync)
操作,它会阻塞当前线程并等待 Block
中的任务执行完毕,然后当前线程才会继续往下运行。
如果是 异步(async)
操作,当前线程会直接往下执行,它不会阻塞当前线程。
放到串行队列的任务,GCD 会 FIFO(先进先出)
地取出来一个,执行一个,然后取下一个,这样一个一个的执行。
放到并行队列的任务,GCD 也会 FIFO
的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。
主队列:这是一个特殊的 串行队列
。什么是主队列,大家都知道吧,它用于刷新 UI,任何需要刷新 UI 的工作都要在主队列执行,所以一般耗时的任务都要放到别的线程执行。
//OBJECTIVE-C
dispatch_queue_t queue = ispatch_get_main_queue();
//SWIFT
let queue = ispatch_get_main_queue()
自己可以创建 串行队列
, 也可以创建 并行队列
。看下面的代码(代码已更新),它有两个参数,第一个上面已经说了,第二个才是最重要的。
第二个参数用来表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL
或 NULL
表示创建串行队列。传入 DISPATCH_QUEUE_CONCURRENT
表示创建并行队列。
//OBJECTIVE-C
//串行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
//SWIFT
//串行队列
let queue = dispatch_queue_create("tk.bourne.testQueue", nil);
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL)
//并行队列
let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT)
全局并行队列
只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
//OBJECTIVE-C
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//SWIFT
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)