1.进程
系统中一个正在运行的应用程序就是一个进程.
比如mac下,正在运行的程序,在活动监视器中表现为一个个进程
问?只有正在运行的应用程序才能称之为一个进程把??
2.多线程
程序最终是由CPU执行的,粗略的说,一个CPU单位时间只能执行一个任务,也就是不能同时刷新UI,又执行下载操作.任务都是在线程中执行的,如果将刷新UI放在一个线程中执行,将下载等耗时操作放在另一线程中执行,那么问题就能够得到解决.然而在单个CPU的硬件条件下,这种同时执行多个任务仍然只是一种幻象,因为其实这只是CPU高速在多个线程之间切换,并不是真正意义上的多个线程同时执行任务.随着硬件的发展,多核的实现,多线程才不在是速度导致的幻象.
粗略的说是这样,我还有许多困惑,比如如何让CPU在多个线程之间切换,线程本质是什么?亦即,代码究竟如何同硬件交互,产生神奇的效果的,但是这不是这里的重点,先略过.
2.1主线程.子线程
程序一旦启动就会创建一条主线程.主线程以外的线程都可以称为子线程或者后台线程.
如图,我在viewDidLoad方法中打了断点,主线程程序一经启动由系统创建,并且默认是串行的(serial)
主线程通常又称为UI线程.主要用于处理和UI相关的操作,如显示界面,相应触摸,点击等事件.
子线程用于处理耗时操作.如下载等....
3.pthread
C语言实现多线程的技术.
用法:
pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict) pthread_t *restrict pthread类型数据的地址 const pthread_attr_t *restrict 通常传NULL void *(*)(void *) 函数的指针,函数名即函数的地址,因而不需要取地址,和数组类似. void *restrict 函数的参数.
使用上面的函数即可创建一个子线程.
例;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { pthread_t pthread = NULL; //创建一个子线程 pthread_create(&pthread, NULL, pthreadOpertion, c); }
//模拟耗时操作 void * pthreadOpertion(void *str) { for (int i = 0; i < 10000; i ++) { NSLog(@"%d",i); } NSLog(@"%s",str); return str; }
4.NSThread
有三种创建子线程的方式
>1.类方法
[NSThread detachNewThreadSelector:@selector(longTimeOperationWithObject:) toTarget:self withObject:@"类方法"];
>2.对象方法
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(longTimeOperationWithObject:) object:@"对象方法"]; [thread start];//将创建的线程加入可调度线程池.CPU才会读取到子线程并执行相应代码.//其他两种由系统将线程加入可调度线程池.
>3.NSObject分类方法
[self performSelectorInBackground:@selector(longTimeOperationWithObject:) withObject:@"NSOject的分类方法"];
//模拟的耗时操作 - (void)longTimeOperationWithObject:(id)obj { NSLog(@"%@----%@",[NSThread currentThread],obj); for (NSInteger i = 0; i < 10000; i ++) { NSLog(@"%ld",i); } }
常用的方法和属性
+ (NSThread *)currentThread;//获取当前线程
+ (BOOL)isMultiThreaded;//是否是子线程
+ (void)sleepUntilDate:(NSDate *)date;//让线程进入休眠状态
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;//同上
+ (void)exit;//结束当前线程
+ (double)threadPriority;//设置线程优先级.只是就概率意义而言.范围在0.0-1.0之间,1.0,优先级最高,仅仅意味着执行该线程的可能性高一些,具体分配取决于CPU
@property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);//线程开销.IOS/OS X的主线程目前默认都是512KB
@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);//是否是主线程
- (void)cancel NS_AVAILABLE(10_5, 2_0);//给线程打上取消标记,通过"@property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);"判断线程状态,如果是取消状态,会终止当前线程
分类方法 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait; // equivalent to the first method with kCFRunLoopCommonModes //上面两个方法都是:在主线程执行aSelector方法,方法的参数为arg,waitUntilDone:(BOOL)wait:是否等到该方法执行结束往下执行.传入YES,需要等到aSelector方法执行完毕,才会继续往下执行,为NO,则不必等aSelector方法执行完即可向下执行,见下面例1 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0); - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0); // equivalent to the first method with kCFRunLoopCommonModes
//上面两个方法都是:在指定的线程中执行任务.
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);//在子线程中执行任务.
例1;
- (void)viewDidLoad { [super viewDidLoad]; [self test]; } - (void)test { [NSThread detachNewThreadSelector:@selector(test2) toTarget:self withObject:nil]; } - (void)test2 { for (NSInteger i = 0; i < 10; i ++) { NSLog(@"%ld",i); } [self performSelectorOnMainThread:@selector(test3) withObject:self waitUntilDone:YES]; //如果为YES,表示需要等到test3执行完才继续往后执行 //如果为NO,表示不需要等到test3执行完就可以继续往后执行/ NSLog(@"test2"); } - (void)test3 { for (NSInteger i = 0; i < 10; i ++) { NSLog(@"%ld",i); } NSLog(@"test3"); }
[self performSelectorOnMainThread:@selector(test3) withObject:self waitUntilDone:YES];为YES输出结果:
2016-03-13 00:15:51.381 NSThread分类方法[2994:123374] 0 2016-03-13 00:15:51.381 NSThread分类方法[2994:123374] 1 2016-03-13 00:15:51.381 NSThread分类方法[2994:123374] 2 2016-03-13 00:15:51.381 NSThread分类方法[2994:123374] 3 2016-03-13 00:15:51.382 NSThread分类方法[2994:123374] 4 2016-03-13 00:15:51.415 NSThread分类方法[2994:123272] 0 2016-03-13 00:15:51.416 NSThread分类方法[2994:123272] 1 2016-03-13 00:15:51.416 NSThread分类方法[2994:123272] 2 2016-03-13 00:15:51.416 NSThread分类方法[2994:123272] 3 2016-03-13 00:15:51.416 NSThread分类方法[2994:123272] 4 2016-03-13 00:15:51.416 NSThread分类方法[2994:123272] test3 2016-03-13 00:15:51.419 NSThread分类方法[2994:123374] test2
为NO输出结果
2016-03-13 00:16:26.380 NSThread分类方法[3015:124168] 0 2016-03-13 00:16:26.382 NSThread分类方法[3015:124168] 1 2016-03-13 00:16:26.382 NSThread分类方法[3015:124168] 2 2016-03-13 00:16:26.383 NSThread分类方法[3015:124168] 3 2016-03-13 00:16:26.383 NSThread分类方法[3015:124168] 4 2016-03-13 00:16:26.383 NSThread分类方法[3015:124168] test2 2016-03-13 00:16:26.416 NSThread分类方法[3015:124065] 0 2016-03-13 00:16:26.416 NSThread分类方法[3015:124065] 1 2016-03-13 00:16:26.416 NSThread分类方法[3015:124065] 2 2016-03-13 00:16:26.416 NSThread分类方法[3015:124065] 3 2016-03-13 00:16:26.416 NSThread分类方法[3015:124065] 4 2016-03-13 00:16:26.417 NSThread分类方法[3015:124065] test3
线程的生命周期
创建----就绪-----运行-----死亡.在运行和死亡之间穿插阻塞(睡眠)
死亡又分为三种;
自然死.任务执行完毕
自杀:[NSThread exit];
他杀:[NSThread cancel],被打上取消标记,