iOS多线程之NSThread的使用

iOS 多线程之NSThread

一、NSThread的属性与方法

1.NSThread 类方法

类方法,顾名思义通过类名直接调用的方法

1. + (void)detachNewThreadWithBlock:(void (^)(void))block   

本方法适用于 ios(10.0),线程的创建,线程创建后直接运行,使用示例如下:

[self detachNewThreadWithBlock:^{

//想要实现的功能

NSLog(@“currentThread:%@”,[NSThread currentThread]);

}];

2. + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;

本方法适用于 ios(10.0)之前版本线程的创建,线程创建后直接运行,使用示例如下:

[self detachNewThreadSelector:@Selector(用此线程执行的函数) toTarget:self withObject:@“想要传入的参数”];

3. + (NSThread *)mainThread; // 获得主线程   

使用示例:NSThread *myMainThread=[NSThread mainThread];

4. + (BOOL)isMainThread; // 判断当前线程是否是主线程

使用示例:BOOL isMain=[NSThread isMainThread];

5. + (BOOL)isMultiThreaded;//判断当前线程是否是多线程

使用示例:BOOL isMulti=[NSThread isMultiThreaded];

6. + (void)sleepUntilDate:(NSDate *)date;//当前线程休眠到指定日期

使用示例:NSDate *myDate=[NSDate dateWithTimeInterval:5 sinceDate:[NSDate date]];

[NSThread sleepUntilDate:myDate];

7. + (void)sleepForTimeInterval:(NSTimeInterval)ti;//当前线程休眠指定时常

使用示例:[NSThreadsleepForTimeInterval:5];

8. + (void)exit;//强行退出当前线程

使用示例:[NSThreadexit];

9. + (double)threadPriority;//获取当前线程线程优先级

使用示例:double dPriority=[NSThread threadPriority];

10. + (BOOL)setThreadPriority:(double)p;//当前线程设定优先级,调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高。

使用示例:BOOL isSetting=[NSThread setThreadPriority:(0.0~1.0)];

11. + (NSArray *)callStackReturnAddresses //线程的调用都会有函数的调用函数的调用就会有栈返回地址的记录,在这里返回的是函 数调用返回的虚拟地址,说白了就是在该线程中函数调用的虚拟地址的数组

使用示例:NSArray* addressArray=[NSThread callStackReturnAddresses];

12.+ (NSArray *)callStackSymbols //同上面的方法一样,只不过返回的是该线程调用函数的名字数字

使用示例:NSArray* nameNumArray=[NSThread callStackSymbols];

注意:callStackReturnAddress和callStackSymbols这两个函数可以同NSLog联合使用来跟踪线程的函数调用情况,是编程调试的重要手段

2.NSthread 实例方法

实例方法,顾名思义通过类对象实例调用的方法

1. - (instancetype)initWithBlock:(void (^)(void))block 

本方法适用于 ios(10.0),线程创建之后等待开始命令在开始运行,使用示例如下:

NSThread *exampleThread=[NSThread alloc]initWithBlock:^{

//想要实现的功能

NSLog(@“currentThread:%@”,[NSThread currentThread]);

}]

[exampleThread start];

2. - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument 

本方法适用于 ios(10.0)之前版本,线程创建之后等待开始命令在开始运行,使用示例如下:

NSThread *exampleThread = [[NSThread alloc] initWithTarget:self selector:@selector(用此线程执行的函数) object:@“想要传入的参数”];  

[exampleThread start];

3.- (BOOL)isMainThread; // 是否为主线程 

使用示例:BOOL isMain=[exampleThreadisMainThread];

4.- (void)setName:(NSString *)n;//设置线程名称

使用示例:[exampleThread setName=@"叶阳"];

5. - (void)cancel ;//取消线程

使用示例:[exampleThread cancel];

6. - (void)start ;//开始执行

使用示例:[exampleThreadstart];

7. - (void)main ;//线程的入口函数

使用示例:[exampleThreadmain];

8. -(void)isExecuting;//判断线程是否正在执行

使用示例:BOOL isRunning=[exampleThread isExecuting];

9. -(void)isFinished;//判断线程是否已经结束

使用示例:BOOL isEnd=[exampleThread isFinished];

10. -(void)isCancelled;//判断线程是否撤销

使用示例:isCancel=[exampleThreadisCancelled];

3.NSObject类的扩展

1.- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)waitmodes:(nullable NSArray<NSString *> *)array;

在主线程上执行函数,wait表示是否阻塞该方法,等待主线程空闲再运行,modes表示运行模式

使用示例:[selfperformSelectorOnMainThread:@Selector(要运行的函数) withObject:@"想要传入的参数" waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array];

2.- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

本函数与上一个函数的kCFRunLoopCommonModes运行模式相同

使用示例:[selfperformSelectorOnMainThread:@Selector(要运行的函数) withObject:@"想要传入的参数" waitUntilDone:(BOOL)wait];

3.- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array 

在指定线程上执行函数,wait表示是否阻塞该方法,等待指定线程空闲再运行,modes表示运行模式

使用示例:[selfperformSelector:@Selector(要运行的函数) onThread:(自己指定的线程)withObject:@"想要传入的参数" waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array];

4.- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait 

本函数与上一个函数的kCFRunLoopCommonModes运行模式相同

使用示例:[selfperformSelector:@Selector(要运行的函数) onThread:(自己指定的线程)withObject:@"想要传入的参数" waitUntilDone:(BOOL)wait];

5.- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg

本函数是隐式创建一个线程并执行

使用示例: [self performSelectorInBackground:@Selector(要运行的函数) withObject:@"想要传入的参数"];


4.NSthread的属性

1.@property (readonly, retain) NSMutableDictionary *threadDictionary;//线程字典
2.@property double threadPriority ; //优先级
3.@property NSQualityOfService qualityOfService ; //线程优先级
NSQualityOfServiceUserInteractive:最高优先级,主要用于提供交互UI的操作,比如处理点击事件,绘制图像到屏幕上
  NSQualityOfServiceUserInitiated:次高优先级,主要用于执行需要立即返回的任务
NSQualityOfServiceDefault:默认优先级,当没有设置优先级的时候,线程默认优先级
  NSQualityOfServiceUtility:普通优先级,主要用于不需要立即返回的任务
  NSQualityOfServiceBackground:后台优先级,用于完全不紧急的任务
4.@property (nullable, copy) NSString *name;线程名称
5.@property NSUInteger stackSize ;//线程使用栈区大小,默认是512K
6.@property (readonly, getter=isExecuting) BOOL executing;//线程正在执行
7.@property (readonly, getter=isFinished) BOOL finished;//线程执行结束
8.@property (readonly, getter=isCancelled) BOOL cancelled;//线程是否可以取消

5.NSThread有三个线程相关的通知

NSWillBecomeMultiThreadedNotification:由当前线程派生出第一个其他线程时发送,一般一个线程只发送一次

NSDidBecomeSingleThreadedNotification:这个通知目前没有实际意义,可以忽略

NSThreadWillExitNotification线程退出之前发送这个通知


二、线程锁

线程锁的使用,主要是为了防止多个线程对同一个对象做操作,造成混乱和错误。
NSLock / NSConditionLock /  NSRecursiveLock / 

@synchronized

    线程锁大都遵循NSLocking协议,这个协议提供了两个线程锁的基本函数

- (void)lock;//加锁

- (void)unlock;//解锁


1.NSLock 

    - (BOOL)tryLock;//尝试加锁,成功返回YES ;失败返回NO ,但不会阻塞线程的运行

    - (BOOL)lockBeforeDate:(NSDate *)limit;

//在指定的时间以前得到锁。YES:在指定时间之前获得了锁;NO:在指定时间之前没有获得锁。

     该线程将被阻塞,直到获得了锁,或者指定时间过期。

  - (void)setName:(NSString*)newName//为锁指定一个Name

  - (NSString*)name//返回锁指定的name

    @property (nullable, copy) NSString *name;线程锁名称 

使用示例:

  NSLock* myLock=[[NSLock alloc]init];

NSString *str=@"hello";

[ NSThread detachNewThreadWithBlock :^{

            [myLock lock];

NSLog(@"%@",str);

str=@"world";

            [myLock unlock];

    }];

[ NSThread detachNewThreadWithBlock :^{

            [myLock lock];

NSLog(@"%@",str);

str=@"变化了";

            [myLock unlock];

    }];


输出结果不加锁之前,两个线程输出一样 hello;加锁之后,输出分辨为hello 与world。

2.NSConditionLock

使用此锁,在线程没有获得锁的情况下,阻塞,即暂停运行,典型用于生产者/消费者模型。

  - (instancetype)initWithCondition:(NSInteger)condition;//初始化条件锁

- (void)lockWhenCondition:(NSInteger)condition;//加锁 (条件是:锁空闲,即没被占用;条件成立)

- (BOOL)tryLock; //尝试加锁,成功返回TRUE,失败返回FALSE

- (BOOL)tryLockWhenCondition:(NSInteger)condition;//在指定条件成立的情况下尝试加锁,成功返回TRUE,失败返回FALSE

- (void)unlockWithCondition:(NSInteger)condition;//在指定的条件成立时,解锁

- (BOOL)lockBeforeDate:(NSDate *)limit;//在指定时间前加锁,成功返回TRUE,失败返回FALSE,

- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;//条件成立的情况下,在指定时间前加锁,成功返回TRUE,失败返回FALSE,

@property (readonly) NSInteger condition;//条件锁的条件

@property (nullable, copy) NSString *name;//条件锁的名称

使用示例:

  NSConditionLock* myCondition=[[NSConditionLock alloc]init];

    [NSThread detachNewThreadWithBlock:^{

        for(int i=0;i<5;i++)

        {

            [myCondition lock];

            NSLog(@"当前解锁条件:%d",i);

            sleep(2);

            [myCondition unlockWithCondition:i];

            BOOL isLocked=[myCondition tryLockWhenCondition:2];

            if(isLocked)

            {

                NSLog(@"加锁成功!!!!!");

                [myCondition unlock];

            }

        }

    }];

输出结果,在条件2 解锁之后,等待条件2 的锁加锁成功。

3. NSRecursiveLock

此锁可以在同一线程中多次被使用,但要保证加锁与解锁使用平衡,多用于递归函数,防止死锁。
- (BOOL)tryLock;//尝试加锁,成功返回TRUE,失败返回FALSE
- (BOOL)lockBeforeDate:(NSDate *)limit;//在指定时间前尝试加锁,成功返回TRUE,失败返回FALSE
@property (nullable, copy) NSString *name;//线程锁名称

使用示例:

 

-(void)initRecycle:(int)value

{

    [myRecursive lock];

    if(value>0)

    {

        NSLog(@"当前的value值:%d",value);

        sleep(2);

        [self initRecycle:value-1];

    }

    [myRecursive unlock];

}

输出结果: 从你传入的数值一直到1,不会出现死锁

4.@synchronized

@synchronized指令做和其他互斥锁一样的工作(它防止不同的线程在同一时间获取同一个锁)

    @synchronized(线程共同使用的对象){

多个线程使用同一个Obj,都会判断Obj是否已被占用,Obj空闲则用,繁忙则等待

    }


使用示例:
NSString *str=@"hello";

  for(int i=0;i<2;i++)

       {

  [NSThread detachNewThreadWithBlock:^{

@synchronized (str) {

     NSLog(@"thread.name:%@------str:%@",str);

     str=@"world";

    }

}];

  }


输出结果不加锁之前,两个线程输出一样 hello;加锁之后,输出分辨为hello 与world。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在网络编程中,多线程编程是一种常用的技术,可以提高程序的并发性和性能。下面是一些关于多线程编程的常用方法和注意事项: 1. NSThreadNSThreadiOS中最底层的线程类,它可以通过类方法或实例方法来创建线程。使用NSThread可以设置线程的名称、优先级,以及控制线程的睡眠和退出等操作。 2. 线程调度:在多线程编程中,多个线程会并发运行,但线程的执行顺序是由CPU调度器决定的,程序员无法控制。多个线程会同时竞争CPU资源,谁先抢到资源谁就先执行,所以多线程的执行顺序是随机的。 3. 多线程的创建:在iOS开发中,常用的多线程编程方式有三种:NSThread、GCD和NSOperation。NSThread是最底层的线程类,可以直接操作线程的各种属性和方法。GCD(Grand Central Dispatch)提供了一种高效的并发编程模型,可以通过队列来管理任务的执行。NSOperation是基于GCD的更高层次的封装,提供了更多的控制和管理线程的功能。 4. 线程的创建顺序:在多线程编程中,并不能保证哪个线程会先运行,即无法确定新创建的线程或调用线程哪个会先执行。新创建的线程可以访问进程的地址空间,并继承调用线程的浮点环境和信号屏蔽字,但挂起信号集会被清除。 总结来说,多线程编程是一种提高程序并发性和性能的技术,在网络编程中尤为重要。通过使用NSThread、GCD或NSOperation等方法,可以实现多线程的创建和管理。然而,程序员无法控制线程的执行顺序,因为线程的调度是由CPU调度器决定的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [IOS多线程基础(OC)](https://blog.csdn.net/yong_19930826/article/details/105857055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [UNIX环境高级编程笔记](https://blog.csdn.net/w_x_myself/article/details/128613534)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值