1、进程 & 线程
#定义与划分尺度:
- 程序的一次执行过程就是进程,它是系统进行资源分配和调度的一个独立单位。
- 线程是进程的一个实体,是进程内的一个执行单元,一个进程至少有一个线程。
#地址空间:
- 进程有自己独立的虚拟地址空间,而线程共享进程的地址空间。
#拥有的资源:
- 进程是资源分配和拥有的单位;同一个进程内的线程共享进程资源。
#执行单位:
#并发:
- 二者均可并发执行(打开多个应用为进程并发;多线程同时执行下载任务为线程并发)。
2、并发 & 并行
1、场景:
并发,一个处理器同时处理多个任务。
并行,多个处理器或多核的处理器同时处理多个不同的任务。
2、概念区分:
并发(Concurrency):在同一时刻只能有一条指令执行,但多个指令被快速的轮换执行,使得在宏观上具有多个线程同时执行的效果,但在微观上并不是同时执行的。
并行(Parallel):在同一时刻,有多条指令在多个处理器上同时执行,无论从微观还是从宏观来看,二者都是一起执行的。
3、多线程
为什么要有多线程?
iOS应用中主线程用来处理界面更新、响应用户触摸事件等。在主线程中执行大量耗时操作会造成主线程阻塞,进而出现卡顿现象以致影响使用和用户体验。故需要将这种耗时操作放到其他的线程中执行。所以多线程编程是防止主线程堵塞,增加运行效率的最佳方法。
为什么不无限制的开辟N条新线程呢?
- 首先,线程的创建需要开销,占用一定得内存空间;
- 其次,有N条线程时处理器需要在多条线程之间频繁调度,这也需要大量开销;
- 最后,N条线程时还需要考虑到这些线程之间的通信和资源共享等问题。
有哪些多线程解决方案?
iOS支持多个层次的多线程编程,层次越高的抽象程度越高,使用也越方便,也是苹果最推荐使用的方法。根据抽象程度由低到高列出如下:
是三种方法里面相对轻量级的,需要自己管理线程的生命周期、同步、加锁问题,这会导致一定的性能开销。
是基于OC实现的,它以面向对象的方式封装了需要执行的操作,不必关心线程管理、同步等问题。NSOperation 是一个抽象基类,iOS提供了两种默认实现:NSInvocationOperation 和 NSBlockOperation,也可以自定义 NSOperation。
- Grand Central Dispatch(简称GCD,iOS4才开始支持):
提供了一些新特性、运行库来支持多核并行编程,它的关注点更高:如何在多个CPU上提升效率。
4、NSThread
4.1.生命周期
#创建
- 实例方法:创建后需要手动调用start函数来启动线程;
1 2 3 4 5
| - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
- (instancetype)initWithBlock:(void (^)(void))block ;
|
第一种实例化方法中,参数selector会在刚创建的线程对象执行start
方法之后被调用,且是在当前新线程中调用。
- 类方法:自动启动线程,无需手动调用start函数。
1 2 3 4 5
| + (void)detachNewThreadWithBlock:(void (^)(void))block ;
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
|
- 分类创建:NSObject(NSThreadPerformAdditions)
1 2
| - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;
|
#就绪
#运行
#阻塞
- 正在运行的线程,可以用休眠或者锁来阻塞线程的执行。
1 2
| + (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti;
|
#死亡
一般情况下(不考虑引用、runloop),线程执行完任务后会自动销毁。也可以在满足某条件后调用exit方法,强制线程退出。
4.2.线程间通信
1 2 3
| [self performSelector:@selector(run)]; [self performSelector:@selector(run) withObject:nil]; [self performSelector:@selector(run) withObject:nil afterDelay:5.0];
|
1 2
| [self performSelector:@selector(run) onThread:newThread withObject:nil waitUntilDone:YES]; [self performSelectorInBackground:@selector(run) withObject:nil];
|
1
| [self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];
|
4.3.线程同步
多个线程同时读写同一份共享资源时,可能会引起冲突。线程同步
是指在一定时间内只允许某一个线程访问某个资源。OC 中实现线程加锁有 NSLock 和 @synchronized 等方式。
1 2 3 4 5 6 7
| NSLock * lock = [[NSLock alloc]init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [lock lock]; // do work [lock unlock]; });
|
- @synchronized()指令对一段代码进行加锁。它需要一个参数,该参数可以是任何的OC对象,包括self。这个对象就是互斥信号量。
1 2 3
| @synchronized(self) { // do work }
|
5、线程保活
默认情况下,子线程在执行完任务之后,会自动销毁。如果想复用此线程或者继续在此线程上执行其他任务,则需要让此线程一直活着而不被销毁;
思路:给子线程所在runloop添加事件源,如端口或自定义source,保证此runloop不退出。需要停止子线程时,停止线程所在runloop即可~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @interface HelThread : NSThread @end
@interface HelThreadHelper : NSObject
-(instancetype)initWithName:(NSString*)name;
- (void)start;
- (void)stop;
-(NSThread *)getThread;
@end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| #import "HelThreadHelper.h"
@implementation HelThread
- (void)dealloc{ NSLog(@"++++THREAD IS DEALLOCED~"); } @end
@interface HelThreadHelper() @property (nonatomic, strong) HelThread *mThread; @property (nonatomic, strong) NSCondition *mConditionLock; @end
@implementation HelThreadHelper
-(instancetype)initWithName:(NSString*)name{ self = [super init]; if (self) { _mConditionLock = [[NSCondition alloc] init]; _mThread = [[HelThread alloc] initWithTarget:self selector:@selector(onThreadInit:) object:nil]; _mThread.name = name; } return self; }
- (void)start{ NSLog(@"+++call Start:%@", [NSThread currentThread]); [_mConditionLock lock]; [_mThread start]; [_mConditionLock wait]; NSLog(@"++runloop Set finised~"); [_mConditionLock unlock]; }
- (void)stop{ [self performSelector:@selector(finish) onThread:_mThread withObject:nil waitUntilDone:NO]; }
-(NSThread *)getThread{ return _mThread; }
- (void)onThreadInit:(id)obj{ NSLog(@"+++runloop Start:%@", [NSThread currentThread]); CFRunLoopSourceContext context = {0}; context.perform = DoNothingRunLoopCallback; CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &context); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); [_mConditionLock lock]; [_mConditionLock signal]; [_mConditionLock unlock]; CFRunLoopRun(); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); CFRelease(source); NSLog(@"+++runloop stop:%@", [NSThread currentThread]); }
- (void)finish{ CFRunLoopStop(CFRunLoopGetCurrent()); }
static void DoNothingRunLoopCallback(void *info){ NSLog(@"+++runloop 回调~"); }
@end
|
调用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #import "HelThreadHelper.h"
@interface ViewController () @property (nonatomic, strong) HelThreadHelper *mHelper; @end
@implementation ViewController
- (void)viewDidLoad { [super viewDidLoad]; _mHelper = [[HelThreadHelper alloc] initWithName:@"com.Hel.MyThread"]; [_mHelper start]; }
- (IBAction)onClick:(id)sender { [self performSelector:@selector(onSel:) onThread:[_mHelper getThread] withObject:nil waitUntilDone:NO]; }
- (IBAction)onStop:(id)sender { [_mHelper stop]; _mHelper = nil; }
- (void)onSel:(id)obj{ NSLog(@"+++call onSel: THREAD:%@",[NSThread currentThread]); }
|
分别点击开始和结束按钮,执行任务和结束线程:
1 2 3 4 5 6
| +++call Start:<NSThread: 0x600003000040>{number = 1, name = main} +++runloop Start:<HelThread: 0x6000030602c0>{number = 5, name = com.Hel.MyThread} ++runloop Set finised~ +++call onSel: THREAD:<HelThread: 0x6000030602c0>{number = 5, name = com.Hel.MyThread} +++runloop stop:<HelThread: 0x6000030602c0>{number = 5, name = com.Hel.MyThread} ++++THREAD IS DEALLOCED~
|