首页 > 其他 > 详细

step 2 NSThread 演练

时间:2016-01-01 20:48:16      阅读:303      评论:0      收藏:0      [点我收藏+]

创建线程的方式

  • 准备在后台线程调用的方法 longOperation:

- (void)longOperation:(id)obj {

    NSLog(@"%@ - %@", [NSThread currentThread], obj);

}

方式1alloc / init - start

- (void)threadDemo1 {

    NSLog(@"before %@", [NSThread currentThread]);

 

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(longOperation:) object:@"THREAD"];

 

    [thread start];

 

    NSLog(@"after %@", [NSThread currentThread]);

}

代码小结

1 [thread start];执行后,会在另外一个线程执行 longOperation: 方法

2 在 OC 中,任何一个方法的代码都是从上向下顺序执行的

3 同一个方法内的代码,都是在相同线程执行的(block除外)

方式2detachNewThreadSelector

- (void)threadDemo2 {

    NSLog(@"before %@", [NSThread currentThread]);

 

    [NSThread detachNewThreadSelector:@selector(longOperation:) toTarget:self withObject:@"DETACH"];

 

    NSLog(@"after %@", [NSThread currentThread]);

}

代码小结

  • detachNewThreadSelector 类方法不需要启动,会自动创建线程并执行 @selector 方法

方式3:分类方法

- (void)threadDemo3 {

    NSLog(@"before %@", [NSThread currentThread]);

 

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

 

    NSLog(@"after %@", [NSThread currentThread]);

}

代码小结

  • performSelectorInBackground 是 NSObject 的分类方法
  • 会自动在后台线程执行 @selector 方法
  • 没有 thread 字眼,隐式创建并启动线程
  • 所有 NSObject 都可以使用此方法,在其他线程执行方法
  • NSThread Target

?                     NSThread 的实例化方法中的 target 指的是开启线程后,在线程中执行 哪一个对象 的 @selector 方法

  • 代码演练

?                     准备对象

  • • @interface Person : NSObject
  • • @property (nonatomic, copy) NSString *name;
  • • @end
  • • @implementation Person
  • • + (instancetype)personWithDict:(NSDictionary *)dict {
  • id obj = [[self alloc] init];
  • [obj setValuesForKeysWithDictionary:dict];
  • return obj;
  • • }
  • • - (void)longOperation:(id)obj {
  • NSLog(@"%@ - %@ - %@", [NSThread currentThread], self.name, obj);
  • • }
  • • @end
  •  

?                     定义属性

  • • @property (nonatomic, strong) Person *person;
  •  

?                     懒加载

  • • - (Person *)person {
  • if (_person == nil) {
  • _person = [Person personWithDict:@{@"name": @"zhangsan"}];
  • }
  • return _person;
  • • }
  • 三种线程调度方法

?                     alloc / init

  • • NSThread *thread = [[NSThread alloc] initWithTarget:self.person selector:@selector(longOperation:) object:@"THREAD"];
  • • [thread start];
  •  

?                     detach

  • • [NSThread detachNewThreadSelector:@selector(longOperation:) toTarget:self.person withObject:@"DETACH"];
  •  

?                     分类方法

  • • [self.person performSelectorInBackground:@selector(longOperation:) withObject:@"PERFORM"];
  • 代码小结

?                     通过指定不同的 target 会在后台线程执行该对象的 @selector 方法

?                     提示:不要看见 target 就写 self

?                     performSelectorInBackground 可以让方便地在后台线程执行任意 NSObject 对象的方法

?                     线程状态

?                                       新建

?                                                         实例化线程对象

?                                       就绪

?                                                         向线程对象发送 start 消息,线程对象被加入 可调度线程池 等待 CPU 调度

?                                                         detach 方法和 performSelectorInBackground 方法会直接实例化一个线程对象并加入 可调度线程池

?                                       运行

?                                                         CPU 负责调度可调度线程池中线程的执行

?                                                         线程执行完成之前,状态可能会在就绪和运行之间来回切换

?                                                         就绪和运行之间的状态变化由 CPU 负责,程序员不能干预

?                                       阻塞

?                                                         当满足某个预定条件时,可以使用休眠或锁阻塞线程执行

?                                                                           sleepForTimeInterval:休眠指定时长

?                                                                           sleepUntilDate:休眠到指定日期

?                                                                           @synchronized(self):乎斥锁

?                                       死亡

?                                                         正常死亡

?                                                                           线程执行完毕

?                                                         非正常死亡

?                                                                           当满足某个条件后,在线程内部中止执行

?                                                                           当满足某个条件后,在主线程中止线程对象

?           代码演练?- (void)statusDemo {

?            

?               NSLog(@"先睡会");

?               [NSThread sleepForTimeInterval:1.0];

?            

?               for (int i = 0; i < 20; i++) {

?                   if (i == 9) {

?                       NSLog(@"再睡会");

?                       [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];

?                   }

?            

?                   NSLog(@"%d %@", i, [NSThread currentThread]);

?            

?                   if (i == 16) {

?                       NSLog(@"88");

?                       // 终止线程之前,需要记住释放资源

?                       [NSThread exit];

?                   }

?               }

?               NSLog(@"over");

?           }

?           ?- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

?               // 注意不要在主线程上调用 exit 方法

?           //    [NSThread exit];

?            

?               // 实例化线程对象(新建)

?               NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(statusDemo) object:nil];

?            

?               // 线程就绪(被添加到可调度线程池中)

?               [t start];

?           }

?                     ?代码小结?阻塞

?                                       方法执行过程,符合某一条件时,可以利用 sleep 方法让线程进入 阻塞 状态

?                                                         sleepForTimeInterval 从现在起睡多少秒

?                                                         sleepUntilDate 从现在起睡到指定的日期

?           死亡?[NSThread exit];

?                      

?                                       一旦强行终止线程,后续的所有代码都不会被执行

?                                       注意1:在终止线程之前,应该注意释放之前分配的对象!

?                                       注意2:线程从就绪运行状态之间的切换是由 CPU 负责的,程序员无法干预

?                    线程属性?代码演练?// MARK: - 线程属性

?                    - (void)threadProperty {

?                        NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];

?                     

?                        // 1. 线程名称

?                        t1.name = @"Thread AAA";

?                        // 2. 优先级

?                        t1.threadPriority = 0;

?                     

?                        [t1 start];

?                     

?                        NSThread *t2 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];

?                     

?                        // 1. 线程名称

?                        t2.name = @"Thread BBB";

?                        // 2. 优先级

?                        t2.threadPriority = 1;

?                     

?                        [t2 start];

?                    }

?                     

?                    - (void)demo {

?                        for (int i = 0; i < 10; ++i) {

?                            // 堆栈大小

?                            NSLog(@"%@ 堆栈大小:%tuK", [NSThread currentThread], [NSThread currentThread].stackSize / 1024);

?                        }

?                     

?                        // 模拟崩溃

?                        // 判断是否是主线程

?                    //    if (![NSThread currentThread].isMainThread) {

?                    //        NSMutableArray *a = [NSMutableArray array];

?                    //

?                    //        [a addObject:nil];

?                    //    }

?                    }

?                                       ?属性?1. name - 线程名称

?                                                         在大的商业项目中,通常需要在程序崩溃时,获取程序准确执行所在的线程

?                                       2. threadPriority - 线程优先级

?                                                         优先级,是一个浮点数,取值范围从 0~1.0

?                                                                           1.0表示优先级最高

?                                                                           0.0表示优先级最低

?                                                                           默认优先级是0.5

?                                                         优先级高只是保证 CPU 调度的可能性会高

?                                                         刀哥个人建议,在开发的时候,不要修改优先级

?                                                         多线程的目的:是将耗时的操作放在后台,不阻塞主线程和用户的交互!

?                                                         多线程开发的原则:简单

?                                       3. stackSize - 栈区大小

?                                                         默认情况下,无论是主线程还是子线程,栈区大小都是 512K

?                                                         栈区大小可以设置

?                    [NSThread currentThread].stackSize = 1024 * 1024;

?                                       ?4. isMainThread - 是否主线程

?                                       资源共享-卖票?多线程开发的复杂度相对较高,在开发时可以按照以下套路编写代码:

?                                                         首先确保单个线程执行正确

?                                                         添加线程

?                    卖票逻辑?- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

?                        self.tickets = 20;

?                     

?                        [self saleTickets];

?                    }

?                     

?                    /// 卖票逻辑 - 每一个售票逻辑(窗口)应该把所有的票卖完

?                    - (void)saleTickets {

?                        while (YES) {

?                            if (self.tickets > 0) {

?                                self.tickets--;

?                                NSLog(@"剩余票数 %d %@", self.tickets, [NSThread currentThread]);

?                            } else {

?                                NSLog(@"没票了 %@", [NSThread currentThread]);

?                                break;

?                            }

?                        }

?                    }

?                    ?添加线程?- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

?                        self.tickets = 20;

?                     

?                        NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];

?                        t1.name = @"售票员 A";

?                        [t1 start];

?                     

?                        NSThread *t2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];

?                        t2.name = @"售票员 B";

?                        [t2 start];

?                    }

?                    ?添加休眠?- (void)saleTickets {

?                        while (YES) {

?                            // 模拟休眠

?                            [NSThread sleepForTimeInterval:1.0];

?                     

?                            if (self.tickets > 0) {

?                                self.tickets--;

?                                NSLog(@"剩余票数 %d %@", self.tickets, [NSThread currentThread]);

?                            } else {

?                                NSLog(@"没票了 %@", [NSThread currentThread]);

?                                break;

?                            }

?                        }

?                    }

?                    ?运行测试结果??互斥锁?添加互斥锁?- (void)saleTickets {

?                     

?                        while (YES) {

?                            [NSThread sleepForTimeInterval:1.0];

?                     

?                            @synchronized(self) {

?                                if (self.tickets > 0) {

?                                    self.tickets--;

?                                    NSLog(@"剩余票数 %d %@", self.tickets, [NSThread currentThread]);

?                                    continue;

?                                }

?                            }

?                     

?                            NSLog(@"没票了 %@", [NSThread currentThread]);

?                            break;

?                        }

?                    }

?                                       ?互斥锁小结

?                                                         保证锁内的代码,同一时间,只有一条线程能够执行!

?                                                         互斥锁的锁定范围,应该尽量小,锁定范围越大,效率越差!

?                                                         速记技巧 [[NSUserDefaults standardUserDefaults] synchronize];

?                                       互斥锁参数

?                                                         能够加锁的任意 NSObject 对象

?                                                         注意:锁对象一定要保证所有的线程都能够访问

?                                                         如果代码中只有一个地方需要加锁,大多都使用 self,这样可以避免单独再创建一个锁对象

?                     原子属性

?                                       原子属性(线程安全),是针对多线程设计的,是默认属性

?                                       多个线程在写入原子属性时(调用 setter 方法),能够保证同一时间只有一个线程执行写入操作

?                                       原子属性是一种单(线程)写多(线程)读的多线程技术

?                                       原子属性的效率比互斥锁高,不过可能会出现脏数据

?                                       在定义属性时,必须显示地指定 nonatomic

?                     代码演练

?                                       定义属性

?           @property (nonatomic, strong) NSObject *obj1;

?           @property (atomic, strong) NSObject *obj2;

?           @property (nonatomic, strong) NSObject *obj3;

?                      

?                                       模拟原子属性

?           @synthesize obj3 = _obj3;

?           - (void)setObj3:(NSObject *)obj3 {

?               @synchronized(self) {

?                   _obj3 = obj3;

?               }

?           }

?            

?           - (NSObject *)obj3 {

?               return _obj3;

?           }

?            

?           * 性能测试

?            

?           - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

?               int largeNumber = 1000 * 10000;

?            

?               NSLog(@"非原子属性");

?               CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();

?               for (int i = 0; i < largeNumber; i++) {

?                   self.obj1 = [[NSObject alloc] init];

?               }

?               NSLog(@"%f", CFAbsoluteTimeGetCurrent() - start);

?            

?               NSLog(@"原子属性");

?               start = CFAbsoluteTimeGetCurrent();

?               for (int i = 0; i < largeNumber; i++) {

?                   self.obj2 = [[NSObject alloc] init];

?               }

?               NSLog(@"%f", CFAbsoluteTimeGetCurrent() - start);

?            

?               NSLog(@"模拟原子属性");

?               start = CFAbsoluteTimeGetCurrent();

?               for (int i = 0; i < largeNumber; i++) {

?                   self.obj3 = [[NSObject alloc] init];

?               }

?               NSLog(@"%f", CFAbsoluteTimeGetCurrent() - start);

?           }

?                     ?原子属性内部的锁是自旋锁,自旋锁的执行效率比互斥锁高??自旋锁 & 互斥锁

?                                       共同点

?                                                         都能够保证同一时间,只有一条线程执行锁定范围的代码

?                                       不同点

?                                                         互斥锁:如果发现有其他线程正在执行锁定的代码,线程会进入休眠状态,等待其他线程执行完毕,打开锁之后,线程会被唤醒

?                                                         自旋锁:如果发现有其他线程正在执行锁定的代码,线程会以死循环的方式,一直等待锁定代码执行完成

?                                       结论

?                                                         自旋锁更适合执行非常短的代码

?                                                         无论什么锁,都是要付出代价

?                     线程安全

?                                       多个线程进行读写操作时,仍然能够得到正确结果,被称为线程安全

?                                       要实现线程安全,必须要用到锁

?                                       为了得到更佳的用户体验,UIKit 不是线程安全的

?                     约定:所有更新 UI 的操作都必须主线程上执行!?

?                                       因此,主线程又被称为UI 线程

?                     iOS 开发建议

?                                       所有属性都声明为 nonatomic

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

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

NSThread中的同步 & 异步

  • 同步
    • 必须等待当前语句执行完毕,才会执行下一条语句
  • 异步
    • 不用等待当前语句执行完毕,就可以执行下一条语句

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    NSLog(@"start");

 

    // 同步执行

//    [self demo];

    // 异步执行

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

 

    NSLog(@"over");

}

 

- (void)demo {

 

    NSLog(@"%@", [NSThread currentThread]);

    [NSThread sleepForTimeInterval:1.0];

    NSLog(@"demo 完成");

}

代码小结

1  同步 从上到下顺序执行

异步 是多线程的代名词

  

step 2 NSThread 演练

原文:http://www.cnblogs.com/fakeCoder/p/5093652.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!