NSThread
1.NSThread
///
(1)+ (NSThread *)currentThread; 当前线程
(2)+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
类方法创建 selector线程执行的方法,只有一个参数,而且不能有返回值
(3)+ (BOOL)isMultiThreaded;判断是否是多线程
(4)@property (readonly, retain) NSMutableDictionary *threadDictionary;
(5)+ (void)sleepUntilDate:(NSDate *)date;线程休眠NSDate给一个休眠到什么时候
(6)+ (void)sleepForTimeInterval:(NSTimeInterval)ti;线程休眠时间
(7)+ (void)exit;结束和退出当前线程
(8)+ (double)threadPriority;获取当前线程的优先级
(9)+ (BOOL)setThreadPriority:(double)p;设置当前线程的优先级
(10)@property double threadPriority NS_AVAILABLE(10_6, 4_0); // To be deprecated; use qualityOfService below
(11)@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); // read-only after the thread is started
(12)+ (NSArray<NSNumber *> *)callStackReturnAddresses NS_AVAILABLE(10_5, 2_0);返回的是这个线程在栈中所占的地址所组成的数组
(13)+ (NSArray<NSString *> *)callStackSymbols NS_AVAILABLE(10_6, 4_0);返回栈空间的符号
(14)@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);设置线程的名字
(15)@property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);
(16)@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);判断指定的线程是否是主线程
(17)+ (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main
(18)+ (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);
(19)- (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
(20)- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
(21)@property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);指定线程是否在执行
(22)@property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);判断线程是否完成
(23)@property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);线程是否被取消
(24)- (void)cancel NS_AVAILABLE(10_5, 2_0);发送线程取消的信号,最终线程是否结束有线程本身决定
(25)- (void)start NS_AVAILABLE(10_5, 2_0); 启动了线程的方法
(26)- (void)main NS_AVAILABLE(10_5, 2_0); // thread body method线程主函数,在线程中执行的函数,都要在main函数中执行。
///
一、NSThread的创建方法有两种,第一个是实例方法,第二个方法是类方法。
(1)- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
(2)+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
参数解释:
1、 selector:线程的执行方法,这个selector只能有一个参数,而且不能有返回值。
2、target:selector消息发送的对象;
3、argument:传输给target的唯一参数,可以是nil;
********************************************************************************************************************
二、不显示的创建线程的方法:
1. 隐式的创建新的线程
[self performSelectorInBackground:@selector(runThread) withObject:nil];
2.在主线程中运行方法,wait表示是否阻塞这个方法的调用,如果为YES则等待主线程中运行方法结束,一般可用于子线程中调用UI的方法。
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];
3. 在指定的线程中执行
[self performSelector:@selector(run) onThread:<#(nonnull NSThread *)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>]
三 一些非线程的调用(NSObject的Category方法)
即在当前线程执行,注意它们会阻塞当前线程(包括UI线程):
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
以下调用在当前线程延迟执行,如果当前线程没有显式使用NSRunLoop或已退出就无法执行了,需要注意这点:
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray*)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
而且它们可以被终止:
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;
********************************************************************************************************************
线程的问题
(1)线程的状态
线程的状态有,新建,就绪,运行,阻塞,退出;
1.线程新建:alloc之后,start之前。进程会为其线程分配内存;
2.线程就绪:调用了start之后,线程会被放到可调度的线程池中,线程就有新建状态转变为就绪状态。这是就有机会获得CPU时间片的机会了。
3.运行:处于就绪状态的线程获得了时间片时,就变成了运行状态;
4.阻塞:当正处于运行状态的线程调用的sleep休眠方法或在等待同步锁时就会被从线程池移到内存中去,即由运行状态变为阻塞状态(Blocked),一旦此线程休眠结束或者获得同步锁,就会被放到线程池中转为就绪状态等待CPU的调度。
5.退出:当处于运行状态的线程任务执行完毕,或者出现异常或者强制退出都会直接导致死亡处于Dead状态。当线程死亡后就会被销毁,从内存中移除。所以一旦线程死亡就永远不可能被在调度。
注释:
1、这里涉及到操作系统的调度策略。同一时间只有一个进程能够在CPU中执行,CPU采用的时时间片轮转的方法对进程进行的调度。因为处理器其实只是一个单核的主线程,不断的在轮流调度处于线程池中的线程,当线程池中的某个线程被调度时是处于运行状态,当此线程被调度执行一个时间片后失去的CPU的处理(因为CPU是轮流调度线程池中的线程的)就会返回到就绪状态。即当CPU调度线程池中的别的线程时当前线程会处于就绪状态,当当前线程被调度时就会处于运行状态。就绪状态和运行状态都是针对线程池中的线程而言的。
2、阻塞状态是针对于处于运行状态的线程而言的,也就是说只有处于运行状态的线程才可能转为阻塞状态。
3、阻塞状态和新建状态是不同的,虽然都是处于内存中。因为处于新建状态的线程不调用start方法是无法被移到线程池中转为就绪状态的。而阻塞状态的线程只有在休眠结束或获得同步锁时才会转为就绪状态。
4、CPU只轮流执行线程池中的线程,即只有就绪状态和运行状态的线程才有可能被执行。
进入就绪状态->运行状态。当线程任务执行完毕,自动进入死亡状态。
-(void)start;
阻塞(暂停)线程 进入阻塞状态
+(void)sleepUntilDate:(NSDate *)date;
+(void)sleepForTimeInterval: (NSTimerInterval) ti;
强制停止线程进入死亡状态
+(void) exit;
图文描述:
(2)线程的同步
http://www.cnblogs.com/wujian1360/archive/2012/03/29/2423375.html
线程同步
一下是从其他的博客中看到的,作为了解
线程的同步方法跟其他系统下类似,我们可以用原子操作,可以用 mutex,lock等。
iOS的原子操作函数是以 OSAtomic开头的,比如:OSAtomicAdd32, OSAtomicOr32等等。这些函数可以直接使用,因为它们是原子操作。
iOS中的 mutex 对应的是 NSLock,它遵循 NSLooking协议,我们可以使用 lock, tryLock, lockBeforeData:来加锁,用 unLock来解锁。使用示例:
BOOL moreToDo = YES;
NSLock *theLock = [[NSLock alloc] init];
...
while (moreToDo) {
/* Do another increment of calculation */
/* until there’s no more to do. */
if ([theLock tryLock]) {
/* Update display used by all threads. */
[theLock unlock];
}
}
我们可以使用指令 @synchronized 来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。
- (void)myMethod:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,在这里就不一一介绍了,大家去看官方文档吧。
用NSCodition同步执行的顺序
NSCodition 是一种特殊类型的锁,我们可以用它来同步操作执行的顺序。它与 mutex 的区别在于更加精准,等待某个 NSCondtion 的线程一直被 lock,直到其他线程给那个 condition 发送了信号。下面我们来看使用示例:
某个线程等待着事情去做,而有没有事情做是由其他线程通知它的。
[cocoaCondition lock];
while (timeToDoWork <= 0)
[cocoaCondition wait];
timeToDoWork--;
// Do real work here.
[cocoaCondition unlock];
其他线程发送信号通知上面的线程可以做事情了:
[cocoaCondition lock];
timeToDoWork++;
[cocoaCondition signal];
[cocoaCondition unlock];
线程间通信
线程在运行过程中,可能需要与其它线程进行通信。我们可以使用 NSObject 中的一些方法:
在应用程序主线程中做事情:
performSelectorOnMainThread:withObject:waitUntilDone:
performSelectorOnMainThread:withObject:waitUntilDone:modes:
在指定线程中做事情:
performSelector:onThread:withObject:waitUntilDone:
performSelector:onThread:withObject:waitUntilDone:modes:
在当前线程中做事情:
performSelector:withObject:afterDelay:
performSelector:withObject:afterDelay:inModes:
取消发送给当前线程的某个消息
cancelPreviousPerformRequestsWithTarget:
cancelPreviousPerformRequestsWithTarget:selector:object:
如在我们在某个线程中下载数据,下载完成之后要通知主线程中更新界面等等,可以使用如下接口:- (void)myThreadMainMethod
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// to do something in your thread job
...
[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
[pool release];
}