iOS:多线程NSThread的详细使用

简介:

NSThread具体使用:直接继承NSObject


NSThread:.
优点:NSThread 是轻量级的,使用简单
缺点:需要自己管理线程的生命周期、线程同步。线程同步对数据的加锁会有一定的系统开销
 
1、属性
           @property (readonly, retain) NSMutableDictionary *threadDictionary;  //线程字典
           @property double threadPriority;                                                  //线程优先级
           @property NSQualityOfService qualityOfService;                           //服务质量
           @property (copy) NSString *name;                                              //线程名字
           @property NSUInteger stackSize;                                               //堆栈大小
           @property (readonly) BOOL isMainThread;                                   //是否是主线程
           @property (readonly, getter=isExecuting) BOOL executing ;              //线程是否正在执行
           @property (readonly, getter=isFinished) BOOL finished;                 //线程是否执行完毕
           @property (readonly, getter=isCancelled) BOOL cancelled ;               //线程是否取消
 
2、通知
           将成为多线程的通知
             FOUNDATION_EXPORT NSString * const NSWillBecomeMultiThreadedNotification; 
            已经成为单线程的通知
           FOUNDATION_EXPORT NSString * const NSDidBecomeSingleThreadedNotification;
            线程将要退出的通知
           FOUNDATION_EXPORT NSString * const NSThreadWillExitNotification;
 
3、主要方法    
               ※当前线程
              + (NSThread *)currentThread;
              ※创建线程的类方法,并添加执行事件

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

             ※是否是多线程

             + (BOOL)isMultiThreaded;

             ※定时休眠

             + (void)sleepUntilDate:(NSDate *)date;

             ※休眠时间

             + (void)sleepForTimeInterval:(NSTimeInterval)ti;

             ※退出线程

            + (void)exit;

            ※线程优先级

           + (double)threadPriority;

           ※设置线程优先级

           + (BOOL)setThreadPriority:(double)p;

           ※显示当前栈内容(返回的是这个线程在栈中所占的地址所组成的数组)

           + (NSArray *)callStackReturnAddresses;

           ※返回栈空间的符号

           + (NSArray *)callStackSymbols;

           ※是否是主线程

           + (BOOL)isMainThread; 

           ※创建线程的实例方法,并添加执行事件

           - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;

           ※取消线程

           - (void)cancel;

           ※启动线程

           - (void)start;

           ※线程主体要执行的方法 :thread body method

           - (void)main;

 
4、类别:@interface NSObject (NSThreadPerformAdditions)     

           ※调用主线程,传入一个与主线程RunLoop循环执行有关的数组

           - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes: (NSArray *)array;

           ※调用主线程更新UI

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

           ※调用指定的线程,传入一个与线程RunLoop循环执行有关的数组

           - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray  *)array;

           ※调用指定的线程更新数据

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

            ※在后台调用线程

           - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;

 

具体举例如下:多线程卖票(要求:把当前票数和当前线程的名字显示在文本视图上)

1.在控件工具中拖拽一个文本视图控件并与类相关联

@property (weak, nonatomic) IBOutlet UITextView *textView;  //拖拽一个文本视图控件并与类关联

2.准备数据,并将文本视图中默认的内容置空

复制代码
    //准备资源
    _tickets = 20;
    
    //将默认文本视图中的内容置空
    self.textView.text = @"";
    
    //取消自动布局,用来控制文本视图的滚动
    self.textView.layoutManager.allowsNonContiguousLayout = NO;
复制代码

3.创建两个线程买票

复制代码
    //创建两个线程并启动线程
    //售票线程-1
    NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
    //设置线程的名字,以区别不同的线程
    [thread1 setName:@"售票线程-1"];
    //启动线程
    [thread1 start];
    
    
    //售票线程-2
    NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
    //设置线程的名字,以区别不同的线程
    [thread2 setName:@"售票线程-2"];
    //启动线程
    [thread2 start];
复制代码

4.为主线程创建一个方法,专门用来更新并显示UI的

#pragma mark -更新UI

复制代码
-(void)appendTextView:(NSString *)text
{
    //1.获取textView中已有的内容
    NSMutableString *stringM = [[NSMutableString alloc]initWithString:self.textView.text];
    
    
    //2.追加新的内容
    [stringM appendString:[NSString stringWithFormat:@"\n%@",text]];
    [self.textView setText:stringM];
    
    //3.调节焦点,滚动视图
    NSRange range = NSMakeRange(stringM.length, 1);
    [self.textView scrollRangeToVisible:range];
}
复制代码

5.为买票线程创建一个方法,负责买票

#pragma mark -卖票的过程

在方法-(void)saleTicket

        {

              while (YES) {

                    执行代码如下:

              }

         }

//当票数大于0时,即if(_tickets>0)时,

操作数据并更新UI为:

复制代码
//并发执行时,采用同步代码块加锁,防止数据在一个线程的操作过程中被另一个线程抢占篡改,锁必须是唯一的
@synchronized(self)
{
  //拼接字符串(当前数据信息)
NSString *str = [NSString stringWithFormat:@"当前票数:%d 当前线程:%@",_tickets,[[NSThread currentThread]name ]]; //调用主线程,更新UI [self performSelectorOnMainThread:@selector(appendTextView:) withObject:str waitUntilDone:YES]; _tickets--; }
复制代码

进行休眠为:

复制代码
//休眠一段时间,模拟耗时操作
if([[[NSThread currentThread]name] isEqualToString:@"售票线程-1"])
{
     [NSThread sleepForTimeInterval:0.3f];
}
else
{
     [NSThread sleepForTimeInterval:0.2f];
}
复制代码

//当票数小于或等于0时,更新UI,并结束线程

复制代码
//拼接字符串(当前数据信息)
NSString *str = [NSString stringWithFormat:@"票已经卖完 当前线程:%@",[[NSThread currentThread]name]];
            
//调用主线程,更新UI
[self performSelectorOnMainThread:@selector(appendTextView:) withObject:str waitUntilDone:YES];
            
break; //结束while死循环,结束线程
复制代码

演示结果如下:

当然,上面采用的是同步代码块隐式处理线程同步的问题,还可以采用显式加锁的方式来防止数据同步。

首先,声明一个NSLock的锁对象

@property (strong,nonatomic)NSLock *lock;

然后将上面的@synchronized(self)代码做修改,如下:

复制代码
//在访问竞争资源前加锁
[self.lock lock];
            
//拼接字符串(当前数据信息)
NSString *str = [NSString stringWithFormat:@"当前票数:%d 当前线程:%@",_tickets,[[NSThread currentThread]name]];
            
//调用主线程,更新UI
[self performSelectorOnMainThread:@selector(appendTextView:) withObject:str waitUntilDone:YES];            
_tickets--;
            
//访问完竞争资源马上解锁
[self.lock unlock];
复制代码

演示结果相同:

 

 

 

 

 

 

 

程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!
分类:  iOS高级

本文转自当天真遇到现实博客园博客,原文链接:http://www.cnblogs.com/XYQ-208910/p/4857689.html,如需转载请自行联系原作者
相关文章
|
2月前
|
安全 调度 数据安全/隐私保护
iOS线程锁
iOS线程锁
27 0
|
3月前
|
API Android开发 iOS开发
安卓与iOS开发中的线程管理对比
【9月更文挑战第12天】在移动应用的世界中,安卓和iOS平台各自拥有庞大的用户群体。开发者们在这两个平台上构建应用时,线程管理是他们必须面对的关键挑战之一。本文将深入探讨两大平台在线程管理方面的异同,通过直观的代码示例,揭示它们各自的设计理念和实现方式,帮助读者更好地理解如何在安卓与iOS开发中高效地处理多线程任务。
|
4月前
|
安全 测试技术 调度
iOS开发-多线程编程
【8月更文挑战第12天】在iOS开发中,属性的内存管理至关重要,直接影响应用性能与稳定性。主要策略包括:`strong`(强引用),保持对象不被释放;`weak`(弱引用),不保持对象,有助于避免循环引用;`assign`(赋值),适用于基本数据类型及非指针对象类型;`copy`(复制),复制对象而非引用,确保不变性。内存管理基于引用计数,利用自动引用计数(ARC)自动管理对象生命周期。此外,需注意避免循环引用,特别是在block中。最佳实践包括理解各策略、避免不必要的强引用、及时释放不再使用的对象、注意block中的内存管理,并使用工具进行内存分析。正确管理内存能显著提升应用质量。
|
4月前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享安卓与iOS开发中的线程管理比较
【8月更文挑战第30天】本文将探讨网络安全与信息安全的重要性,并分享关于网络安全漏洞、加密技术和安全意识的知识。我们将了解常见的网络攻击类型和防御策略,以及如何通过加密技术和提高安全意识来保护个人和组织的信息安全。
|
4月前
|
编译器 C语言 iOS开发
iOS 16 系统键盘修复问题之确定_lock是否用于保护对_deferredTasks的多线程读写如何解决
iOS 16 系统键盘修复问题之确定_lock是否用于保护对_deferredTasks的多线程读写如何解决
|
7月前
获取线程号和杀不死的NSThread线程
获取线程号和杀不死的NSThread线程
35 0
|
iOS开发
iOS多线程之NSOperationQueue-依赖、并发数、优先级、自定义Operation等最全的使用总结
iOS多线程之NSOperationQueue-依赖、并发数、优先级、自定义Operation等最全的使用总结
479 0
|
7月前
|
iOS开发
多线程和异步编程:解释 iOS 中的同步和异步任务的概念。
多线程和异步编程:解释 iOS 中的同步和异步任务的概念。
143 1
|
7月前
|
API 调度 iOS开发
多线程和异步编程:什么是 GCD(Grand Central Dispatch)?如何在 iOS 中使用 GCD?
多线程和异步编程:什么是 GCD(Grand Central Dispatch)?如何在 iOS 中使用 GCD?
78 1
|
安全 调度 C语言
iOS多线程之GCD-同步、异步、并发、串行、线程组、栅栏函数、信号量等全网最全的总结
iOS多线程之GCD-同步、异步、并发、串行、线程组、栅栏函数、信号量等全网最全的总结
998 1