zoukankan      html  css  js  c++  java
  • 多线程——NSThread、GCD、NSOperation

    1、前言:

    一个应用程序就是一个进程,一个进程至少包含一个线程,程序启动会自动创建一个主线程,负责UI界面的现实和控件事件的监控。多线程可以更充分的利用系统CPU资源,一定程度上提升程序的性能。1个进程可以开启多条线程,每条线程可以并行(同时)执行不同的任务。在一个线程内可以包含多个事物(要干的活),在线程内依据先进先出的特性串行执行……

    2、NSThread

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        NSLog(@"main thread is %@",[NSThread mainThread]);//打印主线程(UI线程)
    }
    
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
        //新开辟一条子线程,启动子线程的时候调用downLoad方法,object是传递给子线程调用方法的参数
        NSThread *thread=[[NSThread alloc] initWithTarget:self selector:@selector(downLoad:) object:@"luseike"];
        //给子线程起一个名字
        thread.name=@"thread one";
        //开始子线程
        [thread start];
    }
    
    -(void)downLoad:(NSString *)param{
        //打印当前线程(子线程)及其名字和传递过来的参数
        NSLog(@"begin downLoad--param is %@--current thread is %@ current name is %@",param,[NSThread currentThread],[NSThread currentThread].name);
    }
    

     打印结果如下:

    2014-06-26 23:03:05.724 NSThread[50292:60b] main thread is <NSThread: 0x8c421c0>{name = (null), num = 1}

    2014-06-26 23:03:06.567 NSThread[50292:3807] begin downLoad--param is luseike--current thread is <NSThread: 0xa33c350>{name = thread one, num = 2} current name is thread one

    可以看到主线程的num=1,子线程的num=2,证明确实是新开辟了一条线程来执行downLoad操作。

    还可以通过isMainThread判断是否是主线程,setThreadPriority:(double)p来设置子线程的优先级,优先级的取值范围在0.0~1.0之间,默认是0.5,值越大,优先级越高,被执行的几率越大

    还有两种比较便捷的方式来创建子线程

    1、[NSThread detachNewThreadSelector:@selector(downLoad:) toTarget:self withObject:@"luseike"];//  附加一个线程

    2、[self performSelectorInBackground:@selector(downLoad:) withObject:@"haha"];  //在后台执行一个线程

    这两种方式创建的子线程都不需要调用start方法,系统会自动执行对应的方法,都也都没有机会设置优先级和咸线程名等更详细的设置了,不过这个一般不重要

    3、线程的状态

    线程从生到死大致有下面几种状态:新建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、死亡(dead)

    一个线程被创建之后会放到一个叫做可调度线程池内,等待被CPU调度,当该线程获得CPU的执行权时,就进入到running状态。running状态的线程如果调用sleep方法或者在等待同步锁,就会进入阻塞状态,进入阻塞状态的线程会重新被放到可调度线程池内,等待被重新调度。线程任务执行完毕,或者被强制退出,会进入dead状态,注意:进入dead状态的线程并没有被释放内存,只是不能用了而已,还存在内存中。

    4、控制线程的状态

    启动线程:之前介绍过,调用start方法

    阻塞(暂停)线程:

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

      + (void)sleepForTimeInterval:(NSTimeInterval)ti;

    强制停止线程:+(void)exit;

    多线程的安全隐患:当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。解决的机制就是使用锁(互斥锁),让多条线程同步执行,这就是传说的线程同步技术。值得注意的是:锁定一份代码只用1把锁,用多把锁是没有意义的;线程同步的前提是多条线程抢占同一块资源

    #import "ViewController.h"
    
    @interface ViewController ()
    @property(nonatomic,strong)NSThread *thread1;
    @property(nonatomic,strong)NSThread *thread2;
    @property(nonatomic,strong)NSThread *thread3;
    
    @property(nonatomic,assign)int totalCount;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        self.totalCount=100;
        self.thread1=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
        self.thread2=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
        self.thread3=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    }
    
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
        [self.thread1 start];
        [self.thread2 start];
        [self.thread3 start];
    }
    
    -(void)saleTicket{
        int leftCount=self.totalCount;
        while (leftCount>0) {
            self.totalCount=leftCount--;
            NSLog(@"%@ sale one ticket,left %d",[NSThread currentThread],leftCount);
        }
    } @end

     如上代码,模拟3个子线程同时访问公共资源totalCount,每次操作减一,多线程访问同一资源容易引起的数据安全问题已经说明了,打印部分结果如下

    2014-06-26 23:51:33.639 NSThread[63065:360b] <NSThread: 0xa06dd50>{name = (null), num = 3} sale one ticket,left 99

    2014-06-26 23:51:33.639 NSThread[63065:3707] <NSThread: 0xa0706e0>{name = (null), num = 2} sale one ticket,left 99

    2014-06-26 23:51:33.639 NSThread[63065:3f03] <NSThread: 0xa06ddf0>{name = (null), num = 4} sale one ticket,left 99

    可以看到三个子线程都操作了totalCount变量,每次操作之后的值却没有变化……

    互斥锁的使用格式:

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

    -(void)saleTicket{
        while (1) {
            @synchronized(self) { // 加锁(只能用一把锁)
                // 1.先检查票数
                int count = self.totalCount;
                if (count > 0) {
                    self.totalCount = count - 1;
                    
                    NSThread *current = [NSThread currentThread];
                    NSLog(@"%@ sale one ticket, left %d tickets", current, self.totalCount);
                } else {
                    [NSThread exit];
                }
            } 
        }
    }
    

     打印结果就可以正常显示了……

    5、GCD简介

    GCD是苹果为了多核的并行运算提出的解决方案,会自动管理线程的生命周期,程序员只需要告诉GCD要执行什么任务,不需要编写任何线程管理代码。GCD中两个核心概念:任务、队列,将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行,任务的取出遵循队列FIFO原则:先进先出,后进后出。

    GCD的队列可以分为2大类型:并发队列(可以让多个任务并发执行)、串行队列

  • 相关阅读:
    开发win8 metro monogame,显示pubcenter广告时会使游戏卡住的问题的解决方法。
    win8商店应用验证,二进制文件是在调试模式下生成的解决方案。
    slxna,游戏页面切到后台回来后返回sl页面导致sl页面无响应,解决方法。
    支持虚拟化也开来虚拟化就是装不上HyperV的解决方法
    WP中一些耗时的东西
    WP自定义字体
    SystemTray文字颜色问题
    longlistselector 闪烁问题研究
    vs2013安装xna4.0模板
    让textbox紧贴IME
  • 原文地址:https://www.cnblogs.com/luseike/p/3811128.html
Copyright © 2011-2022 走看看