zoukankan      html  css  js  c++  java
  • iOS 多线程NSThread理解与场景示例

    NSThread是相对GCD和NSOperationQuene而言,比较轻量级的一种多线程处理方式。

    但同时,它的弊端就是需要自己管理线程的生命周期,以及线程同步;而另外两种不需要自己管理。

    常见方法介绍:

    一、获取当前线程

    NSThread *current = [NSThread currentThread];

    二、获取主线程

    NSThread *main = [NSThread mainThread];

    三、NSThread的创建

    1 // 初始化线程
    2 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"aaa"];
    3 // 开启线程
    4 [thread start];

    .静态方法

    + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@""];

    执行完上面代码后会马上启动一条新线程,并且在这条线程上调用self的run方法。

    .隐式创建线程

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

    会隐式地创建一条新线程,并且在这条线程上调用self的run方法。

    四、暂停当前线程

    [NSThread sleepForTimeInterval:2];
    NSDate *date = [NSDate dateWithTimeInterval:2 sinceDate:[NSDate date]];  
    [NSThread sleepUntilDate:date];

    上面两种做法都是暂停当前线程2秒

    退出线程

    [NSThread exit]; 

    五、线程的其他操作

    1.在指定线程上执行操作

    1 [self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES]; 

    * 上面代码的意思是在thread这条线程上调用self的run方法

    * 最后的YES代表:上面的代码会阻塞,等run方法在thread线程执行完毕后,上面的代码才会通过

    2.在主线程上执行操作

    [self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];  

    在主线程调用self的run方法

    3.在当前线程执行操作

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

    在当前线程调用self的run方法

    场景1:

    异步下载一张图片,下载完在UI显示。

    代码实现:

    //开启子线程下载
    [NSThread detachNewThreadSelector:@selector(downloadPic) toTarget:self withObject:nil];
    //下载图片 -(void)downloadPic{ NSURL *url = [NSURL URLWithString:@"https://res.wx.qq.com/mpres/htmledition/images/mp_qrcode218877.gif"]; NSData *pic = [NSData dataWithContentsOfURL:url]; UIImage *img = [UIImage imageWithData:pic]; //回到主线程显示 [self performSelectorOnMainThread:@selector(showImg:) withObject:img waitUntilDone:YES]; } -(void)showImg:(UIImage *)image{ //imageView.image = image NSLog(@"显示 pic"); }

      

    六、多线程安全与加锁

       说明:多线程访问同一个资源的时候可能会出现数据错乱等安全问题,解决方法是对必要的代码段进行加锁。

       注意:在OC中加互斥锁使用@synchronized(self) {},在swift可以使用objc_sync_enter(self)和objc_sync_exit(self)方法,注意这两个方法必须成对使用,把要加锁的代码放在中间.

    场景1:

    以售票为例:3个售票员同时售票,票总数为10。

    - (void)sailTicket {
        NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
        NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
        NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
        thread1.name = @"售票员1";
        thread2.name = @"售票员2";
        thread3.name = @"售票员3";
        [thread1 start];
        [thread2 start];
        [thread3 start];
        
    }
    
    -(void)sale{
        while (1) {
            @synchronized (self) {
                for (int i = 0; i<10000; i++) {
                    //模拟延迟
                }
                
                if (_ticketCount>0){
                    _ticketCount--;
                    NSLog(@"%@卖出了一张票,余票还有%lu",[NSThread currentThread].name,(unsigned long)_ticketCount);
                }else{
                    NSLog(@"票已售完");
                    break;
                }
            }
        }
        
        
    }

    可以很明显看出,每个售票员都是严格按照从10递减的方式售票,不存在票数忽多忽少的情况。

    如果不加锁:

      

  • 相关阅读:
    096实战 在windows下新建maven项目
    095实战 ETL的数据来源,处理,保存
    094实战 关于js SDK的程序,java SDK的程序
    093实战 Nginx日志切割,以及脚本上传nginx的切割日志
    092实战 数据收集(各种事件)
    091实战 Nginx配置(日志服务器中关于日志的产生)
    android64位机子兼容32位.so库文件
    给 Android 初学者的 Gradle 知识普及
    Android重力感应开发
    随笔之Android平台上的进程调度探讨
  • 原文地址:https://www.cnblogs.com/yajunLi/p/6276996.html
Copyright © 2011-2022 走看看