NSThread使用详解

上一节中,我转载他人的文章,对多线程的理论知识进行了大致的描述,如果想了解的话,请点击这里。接下来的几节内容,我将一一介绍各自的使用。

1. NSThread相关的主要方法:

创建、启动线程

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
// 线程一启动,就会在线程thread中执行self的run方法

主线程相关方法

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

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

得到当前线程、获取线程名字

NSThread *current = [NSThread currentThread];
- (void)setName:(NSString *)name;
- (NSString *)name;

创建线程后自动启动线程

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

隐式创建并启动线程

[self performSelectorInBackground:@selector(run) withObject:nil];

2. 线程状态示意图

3. 互斥锁

@synchronized(锁对象) { // 需要锁定的代码  }

注意:锁定1份代码只用1把锁,用多把锁是无效的

互斥锁的优缺点

优点:能有效防止因多线程抢夺资源造成的数据安全问题

缺点:需要消耗大量的CPU资源

互斥锁的使用前提:多条线程抢夺同一块资源

相关专业术语:线程同步

线程同步的意思是:多条线程按顺序地执行任务

互斥锁,就是使用了线程同步技术

4. 原子性和非原子性

OC在定义属性时有nonatomic和atomic两种选择

atomic:原子属性,为setter方法加锁(默认就是atomic)

nonatomic:非原子属性,不会为setter方法加锁

atomic加锁原理

@property (assign, atomic) int age;
- (void)setAge:(int)age
{
    @synchronized(self) {
        _age = age;
    }
}

nonatomic和atomic对比

atomic:线程安全,需要消耗大量的资源

nonatomic:非线程安全,适合内存小的移动设备

iOS开发的建议

所有属性都声明为nonatomic

尽量避免多线程抢夺同一块资源

尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

5. 线程间通信

什么叫做线程间通信

在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信

线程间通信的体现

1个线程传递数据给另1个线程

在1个线程中执行完特定任务后,转到另1个线程继续执行任务

线程间通信常用方法

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

线程间通信示例 – 图片下载

6. Demo 演示

业务描述(卖票): 模拟两个线程抢夺一份资源

运行结果图:

主要代码说明:

1.  属性及方法定义:

/*
    1. NSThread 可以使用NSLock 进行加锁工作
    2. NSOperation和GCD  应该使用同步锁 :@synchronized(self),并且抢夺的内存资源应该定义为 atomic 的属性
 */
@property (atomic,assign) int tickets;
@property (atomic,strong) NSLock *lock;
//  显示结果区域
@property (weak, nonatomic) IBOutlet UITextView *messageBoard;
//  开始售票
- (IBAction)threadSale;

2.  点击Start对应方法的代码:

- (IBAction)threadSale {
    // 1. 先设定销售票的数量
    _tickets = 100;

    // 创建线程1
    NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSaleMethod) object:nil];
    // 便于跟踪时知道谁在工作
    thread1.name = @"售票线程-1";
    // 启动线程
    [thread1 start];

    // 创建线程2
    NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSaleMethod) object:nil];
    thread2.name = @"售票线程-2";
    [thread2 start];
}

3.  子线程执行内容对应的方法

- (void)threadSaleMethod {
    // 1. 定义锁,懒加载
    if (_lock == nil) {
        _lock = [[NSLock alloc] init];
    }

    while(YES)
    {
        [_lock lock];
        if(_tickets > 0)
        {
            NSString *message = [NSString stringWithFormat:@"当前票数是%d,售票线程是%@",_tickets,[[NSThread currentThread] name]];
            // 更新UI的工作,一定要放在主线程中完成
            // waitUntilDone 的意思是:是否等待主线程更新完毕
            [self performSelectorOnMainThread:@selector(appendTextView:) withObject:message waitUntilDone:YES];

            _tickets--;

            // 当前线程执行完毕,解锁
            [_lock unlock];

            // 模拟延时
            if ([[[NSThread currentThread] name] isEqualToString:@"售票线程-1"]) {
                [NSThread sleepForTimeInterval:0.2];
            } else {
                [NSThread sleepForTimeInterval:0.3];
            }
        }
        else{
            // 在退出之前需要解锁
            [_lock unlock];

            // 结束信息
            NSString *str = [NSString stringWithFormat:@"票已售完%@", [[NSThread currentThread] name]];
            [self performSelectorOnMainThread:@selector(appendTextView:) withObject:str waitUntilDone:YES];

            break;

        }
    }
}

4.  更新主线程UI对应的方法

- (void)appendTextView:(NSString *)text {
    NSMutableString *str = [NSMutableString stringWithString:self.messageBoard.text];
    [str appendFormat:@"\n%@", text];

    self.messageBoard.text = str;

    // 用来将文本框滚动到想要的位置
    // 我们现在想要滚动到最后,这个方法的参数是一个NSRange
    NSRange range = NSMakeRange(str.length, 1);
    [self.messageBoard scrollRangeToVisible:range];
}

这一节,我详细的介绍了线程的主要概念及NSThread的使用,下一节将为大家介绍GCD的概念及使用。

时间: 2024-10-14 11:04:22

NSThread使用详解的相关文章

NSThread 详解

第一.iOS主线程专门用来更新显示UI界面.处理用户触摸事件的,所以不能阻塞主线程,否则带来极坏的用户体验. 一般的解决方案就是将那些耗时的操作放到另外一个线程中去执行. NSThread *red=[NSThread currentThread]; //获取当前线程 NSThread *mainThread=[NSThread mainThread]; //获取主线程 [red setName:@"hello"];   //设置线程名称 if ([red isMainThread])

iOS GCD NSOperation NSThread等多线程各种举例详解(拷贝)

2年多的iOS之路匆匆而过,期间也拜读来不少大神的博客,近来突然为自己一直做伸手党感到羞耻,是时候回馈社会.回想当年自己还是小白的时候,照着一些iOS多线程教程学,也只是照抄,只知其然.不知其所以然.现写一篇详细教程奉献给广大读者.废话就不多说了,直接上干货.如下图列举了很多多线程的知识点,每个知识点都写有对应的详细例子,并对运行结果进行分析,绝对拿实践结果来说话.如果各位道友发现错误之处还请指正.附上demo下载地址 iOS中几种多线程的比较 GCD:是苹果为多核的并行运算提出的解决方案,所以

iOS多线程实现方案详解01——NSThread

NSThread 一.创建和启动线程 1.开线程的几种方式 1)先创建线程,后启动 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start]; 2)创建线程后自动直接启动 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; [sel

转载iOS--->NSRunLoop详解

转载--->NSRunLoop(详解) NSRunLoop大部分情况在多线程编程的时候才会用到..但是一般不会用NSRunLoop,因为它不是线程安全的.一般都建议用CFRunLoop,这个是线程安全的.input source and port-based custom source这些操作,是向线程里面添加操作的.添加的这些操作,会在该线程执行空间的调度下执行. 通俗的理解就是如果你创建的了一个子线程,子线程的运行函数如下- (void) subThread (void*)unused { 

AFNetwork 作用和用法详解

AFNetworking是一个轻量级的iOS网络通信类库.它建立在NSURLConnection和NSOperation等类库的基础上,让很多网络通信功能的实现变得十分简单.它支持HTTP请求和基于REST的网络服务(包括GET.POST. PUT.DELETE等).支持ARC. Github地址:https://github.com/AFNetworking/AFNetworking // // MJViewController.m // 03.AFN演练 // // Created by a

iOS网络编程(六) NSURLSession详解

昨夜浏览Demo的时候,看到别人请求网络数据用的是NSURLSession,当时就在想这里什么,怎么没有用过,引起了我的好奇心,遂去百度-谷歌-官方文档一一查看,有了一定的了解,原来NSURLSession是iOS7中新的网络接口,它与咱们熟悉的NSURLConnection是并列的. 查找资料,写了一个小Demo,大家可以看看,有什么不足的地方,可以留言帮我指出来. // // HMTRootViewController.m // // // Created by HMT on 14-6-7.

iOS---NSAutoreleasePool自动释放原理及详解

当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池.它仍然是个正当的对象,因此自动释放池 定义的作用域内的其它对象可以向它发送消息.当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放. 1. ojc-c 是通过一种"referring counting"(引用计数)的方式来管理内存的, 对象在开始分配内存(alloc)的时候引用计数为一,以后每当碰到有copy,retain的时候引用计数都会加一, 每当

iOS开发——多线程OC篇&多线程详解

多线程详解 前面介绍了多线程的各种方式及其使用,这里补一点关于多线程的概念及相关技巧与使用,相信前面不懂的地方看了这里之后你就对多线程基本上没有什么问题了! 1——首先ios开发多线程中必须了解的概念: 进程 正在进行中的程序被称为进程,负责程序运行的内存分配 每一个进程都有自己独立的虚拟内存空间 线程 线程是进程中一个独立的执行路径(控制单元) 一个进程中至少包含一条线程,即主线程 可以将耗时的执行路径(如:网络请求)放在其他线程中执行 创建线程的目的就是为了开启一条新的执行路径,运行指定的代

《招一个靠谱的移动开发》iOS面试题及详解(上篇)

多线程.特别是NSOperation 和 GCD 的内部原理. 运行时机制的原理和运用场景. SDWebImage的原理.实现机制.如何解决TableView卡的问题. block和代理的,通知的区别.block的用法需要注意些什么. strong,weak,retain,assign,copy nomatic 等的区别. 设计模式,mvc,单利,工厂,代理等的应用场景. 单利的写法.在单利中创建数组应该注意些什么. NSString 的时候用copy和strong的区别. 响应值链. NSTi