NSThread
使用更加面向对象,是OC,简单易用,可直接操作线程对象 ,线程的生命周期归属于程序员管理
在iOS领域中真正的多线程技术就是pthread
和NSThread
,那么GCD
呢,GCD
不能直接操作线程,是封装好的并发技术,它是操作队列,和线程不管,特别安全,NSOperation
也是一样的,所以多线程技术只有两个pthread
和NSThread 苹果官方并不鼓励开发者使用多线程技术,而是推荐并发技术,这也是为什么苹果主推
GCD`的原因
关于创建线程
1.
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument
2.
- (instancetype)initWithBlock:(void (^)(void))block
3.
+ (void)detachNewThreadWithBlock:(void (^)(void))block
4.
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
5.
NSThread * t=[[NSThread allloc] init]
[t start];
如上运行不起来
[[NSThread allloc] init] 这个只适合NSThread子类也就是自定义的NSThread
前两种方法是对象方法,创建完成之后需要start
,而有两种方法是类方法detach
表示分派,就是直接运行新的线程了
还有几个方法,不在NSThread
的头文件里
它们是NSObject
的分类
所以它很方便,意味着所有的基础的NSObject
都可以调用这个如下方法,不需要创建NSThread
对象
- (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
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg
代码出来
如上的方法,aSelector方法会不会执行,要看onThread的线程是否还在,如果线程已经被执行完了那么aSelector方法就不会被调用
1.
[self performSelectorInBackground:@selector(test) withObject:nil];
test方法就是在后台(子线程)里执行
线程的状态
先po出一张图
image.png
线程创建了之后,存放在内存中的可调度线程池
中,这个可调度线程池
我们好像是不能操作的,是有CPU
进行调度的
当我们Start
方法的时候,线程会被放入可调度线程池
中,此时的状态是Runnable
就绪状态,当CPU
调度这个线程的时候,那么它的状态是运行状态
,当CPU
调度其他线程的时候,那么它的状态又是Runnable
就绪状态,当线程在运行状态
的时候我们通过sleep
方法或者等待同步锁(线程被锁在外面了)让线程称为阻塞Blocked
的状态,当线程在阻塞状态
的时候,线程不在可调度线程池
,当前sleep
时间到了或者锁开了,此线程又回到了可调度线程池
称为Runnable
就绪状态等待被调度,当任务执行完毕了或者强制退出或者出现异常,此时线程的状态是死亡
的状态,线程会被从可调度线程池
拿出来然后再被干掉
线程的状态的可控性
如上图所示
可控的状态,只有Start
,Runnable
就绪状态,阻塞Blocked
的状态,死亡
的状态
设计到CPU
怎么调度的都不是我们可控的
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//创建线程
NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTest) object:nil];
//线程就绪状态 (cpu 翻牌)
[thread start];
}
-(void)threadTest{
//阻塞 让线程睡会儿
//方法:sleep 是类方法 会直接休眠当前线程 当前线程是t线程
[NSThread sleepForTimeInterval:2];
for (int i = 0; i<20; i++) {
NSLog(@"%@ ->%d",[NSThread currentThread],i);
if (i==10) {
//当线程满足一定条件的时候,可以强行终止线程
//exit 是类方法 终止的是当前的线程
/*
一旦强行终止线程 后续的所有代码将不会被执行
如果线程是主线程 那么主线程是没法被杀掉的,但是会让主线程阻塞,但是阻塞之后,就没法重新开启,所以相当于杀死一样的效果,只不过app还活着
所以注意了:在终止线程之前,如果我们分配的对象,我们应该再exit之前释放他们
*/
[NSThread exit];
}
}
}
NSThread的属性
-
name:线程名,没什么大用,不过在捕捉奔溃时候 能看到是在那条线程奔溃的
-
threadPriority :优先级级别 0-1 级别越高,只是保证CPU调度的可能性会高一点,在多线程的开发中,不建议修改优先级
在多线程的开发中,不要相信一次的运行结果
多线程的安全隐患(资源共享)
一个资源可能同时会被多个线程共享,也就是多个线程可能会访问同一个资源,比如多个线程访问同一个对象,同一个变量,同一个文件,当多个线程访问同一个资源时,很容易引发数据错乱和数据安全问题
解决资源共享的问题
- 互斥锁
互斥锁--保证锁内的代码,同一时间只有一条线程可执行
互斥锁的范围应该尽量小,范围大了,效率就差
//参数:self 或者任何oc对象都可以
@synchronized(self){
//加锁的内容
}
//
NSObject * lock = [NSObject new];
@synchronized(lock){
//加锁的内容
}
这就是锁不住,不是说了任何oc对象都可以嘛,因为lock是局部变量,每次进来都是重新创建,归当前线程单独拥有,除非用全部变量,但是一般用self
网友评论