zoukankan      html  css  js  c++  java
  • iOS-----多线程之NSThread

         多线程

    iOS平台提供了非常优秀的多线程支持,程序可以通过非常简单的方式来启动多线程,iOS平台不仅提供了NSThread类来创建多线程,还提供了GCD方式来简化多线程编程,提供了NSOperation和NSOperationQueue支持多线程编程。总之,iOS已经尽力降低开发多线程应用的繁琐,努力让开发者能轻松、简单地开发多线程应用.

    线程概述

    几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程.当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程.

    任务->进程->线程

    线程和进程

    所有运行中的任务通常对应一个进程(Process),当一个程序进入内存运行后,即变成一个进程,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位。

    进程包含如下3个特征

    独立性

    进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间。

    动态性

    进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念,进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的。

    并发性

    多个进程可以在单个处理器上并发执行,多个线程之间不会互相影响。

    并发性(concurrency)和并行性(parallel)是两个概念,

    并行指在同一时刻,有多条指令在多个处理器上同时执行;

    并发指在在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

    线 程

    多线程使得同一个进程可以同时并发处理多个任务。线程(Thread)也被称作轻量级进程(Lightweight Process),线程是进程的执行单元。线程在程序中是独立的、并发的执行流。当进程被初始化后,主线程就被创建了。对于绝大多数的应用程序来说,通常仅要求有一个主线程,但是我们也可以在该进程内创建多条顺序执行流,这些顺序执行流就是线程,每条线程也是互相独立的。

    线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不再拥有系统资源,它与父进程的其他线程共享该进程所拥有的全部资源。因为多个线程共享父进程里的全部资源,因此编程更加方便;但必须更加小心,我们必须确保线程不会妨碍同一进程里的其他线程

    简而言之:一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少要包含一个线程.操作系统可以同时执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程.

    多线程的优势

    线程在程序中是独立的、并发的执行流,与分隔的进程相比,进程中的线程之间的隔离程度要小。它们共享内存、文件句柄和其他每个进程应用的状态。同一个进程中的线程都有共性----多个线程将共享同一个进程虚拟空间。线程共享的环境包括:进程代码段、进程的公有数据等。利用这些共享的数据等,线程很容易实现相互之间的通信。

    多线程的优点

    1

    进程间不能共享内存,但线程之间共享内存非常容易。

    2

    系统创建进程需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发比多进程的效率高。

    3

    iOS提供了多种多线程实现方式,从而简化了iOS的多线程编程。

    iOS大致提供了如下3种多线程编程的技术

    1

    使用NSThread实现多线程。

    2

    使用NSOperation与NSOperationQueue实现多线程

    3

    使用GCD(Grand Central Dispatch)实现多线程

    使用NSThread实现多线程

    iOS使用NSThread类代表线程,创建新线程也就是创建NSThread对象。

    创建和启动线程

    创建NSThread有两种方式。

    -(id)initWithTarget:(id)target selector:(SEL)selector object:(id)arg

    创建一个新线程对象

    + (void)detachNewThreadSelector:(SEL)selector object:(id)target withObject:(id)arg

    创建并启动新线程

    + currentThread:

    currentThread是NSThread类的类方法,该方法总是返回当前正在执行的线程对象

    setName:

    可以通过name方法返回指定线程的名字

    上面两种方式的本质都是将target对象的selector方法转换为线程执行体,其中selector方法最多可以接收一个参数,而arg就代表传给selector方法的参数.

    target对象的selector方法的方法体代表了线程需要完成的任务,因此相当于把target对象的selector方法转换为线程执行体.

      第1种方式是一个实例方法,该方法返回一个NSThread对象,必须调用start方法启动线程

      第2种方式不会返回NSThread对象,因此这种方式直接创建并启动线程.

         

    线程的状态

    启动线程使用start方法,线程启动之后并不是立即进入运行状态,线程被启动后处于就绪状态,当系统调整线程后,线程才会进入运行状态.

    如果程序希望调用子线程的start方法后子线程立即开始执行,程序可以使用[NSThread sleepForTimeInterval:0.001];

    让当前运行的线程(主线程)睡眠1毫秒---1毫秒就够了,因为在这1毫秒内CPU不会空闲,它会去执行另一个处于就绪状态的线程,这样就可以让子线程立即获得执行.

    终止子线程

    线程会以以下3种方式之一结束,结束后就处于死亡状态.

      线程执行体方法执行完成,线程正常结束.

      线程执行过程中出现错误

      直接调用NSThread类的exit方法来中止当前正在执行的线程.

    注意

    当主线程结束时,其他线程不受任何影响,并不会随之结束.一旦子线程启动起来后,它就拥有和主线程相同的地位,它不会受主线程的影响.

    为了测试某个线程是否正在运行,可以调用线程对象的isExcuting、isFinished方法,当线程正处于执行过程中时,调用isExecuting方法就会返回YES;当线程执行完成后,调用isFinished方法就会返回YES。

     

      上面程序中①号代码调用了thread对象的cancel方法,该方法用于向thread对象发送取消信号,这样即可使得thread对象的isCancelled方法

    返回YES------接下来程序在线程执行体方法中线判断thread对象d的isCancelled是否为YES,如果该对象的isCancelled为YES,程序就调用Thread类的exit方法终止当前正在执行的循环,这样就可以从UI线程终止子线程了.

    线程睡眠

    需要让当前正在执行的线程暂停一段时间,并进入阻塞状态,则可以通过调用NSThread类的静态。sleepXxx方法来完成。

    NSThread类提供了如下两个控制线程暂停的类方法

    +(void)sleepUntilDate:(NSDate *)aDate:

    让当前正在执行的线程暂停到aDate代表的时间,并进入阻塞状态

    +(void)sleepForTimeInterval:(NSTimeInterval)ti:

    让当前正在执行的线程暂停ti秒,并进入阻塞状态.

    当当前线程调用sleepXxx方法进入阻塞状态后,在其睡眠时间段内,该线程不会获得执行的机会,即使系统中没有其他科执行的线程,处于阻塞状态的线程也不会执行,因此sleepXxx方法常用来暂停线程的执行.

    [NSThread sleepForTimeInterval:0.5];

    用于控制当前正在执行的线程暂停0.5秒

    改变线程优先级

    每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会.每个子线程默认的优先级为0.5.

    NSThread提供了如下实例方法和类方法来设置获取线程的优先级

    + threadPriority:

    该类方法获取当前正在来设置执行的线程的优先级

    - threadPriority:

    该实例方法获取调用该方法的线程对象的优先级

    + setThreadPriority:(double)priority:

    该类方法用于设置当前正在执行的线程的优先级

    -  setThreadPriority:(double)priority:

    该实例方法用于设置该方法的线程对象的优先级

     在上面方法中,setThreadPriority:(double)priority方法的参数可以是一个double类型的浮点数,范围为0.0~1.0,其中1.0代表最高优先级,0.0代表最低优先级.

    下面代码中使用了setThreadPriority:方法来改变主线程的优先级,并使用该方法改变了两个线程的优先级,从而可以看到高优先级的线程将会获得更多的执行机会.

    代 码

    片段

     1 @implementation LCViewController
     2 
     3 - (void)viewDidLoad
     4 
     5 {
     6 
     7    [super viewDidLoad];
     8 
     9    NSLog(@”线程A的优先级为:%g”,[NSThread threadPriority]);
    10 
    11    // 创建第1个线程对象
    12 
    13   NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector@selector(run) object:nil];
    14 
    15    // 设置第1个线程对象的名字
    16 
    17   thread1.name = @”线程A”;
    18 
    19   NSLog(@”线程A的优先级为: %g”, thread1.threadPriority);
    20 
    21   // 设置使用最低优先级
    22 
    23   thread1.threadPriority = 0.0;
    24 
    25   // 创建第2个线程对象
    26 
    27   NSThread* thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    28 
    29   // 设置第2个线程对象的名字
    30 
    31   thread2.name = @”线程B”;
    32 
    33   NSLog(@”线程B的优先级为:%g”, thread2.threadPriority);
    34 
    35   // 设置使用最高优先级
    36 
    37   thread2.threadPriority = 1.0;
    38 
    39   // 启动两个线程
    40 
    41   [thread1 start];
    42 
    43   [thread2 start];
    44 
    45 }
    46 
    47 - (void)run
    48 
    49 {
    50 
    51    for(int i= 0; i < 100; i++)
    52 
    53 {
    54 
    55      NSLog(@”----%@-----%d”,[NSThread currentThread].name, i);
    56 
    57 }
    58 
    59 }
    60 
    61 @end

    // 上面程序在改变线程A、线程B的优先级之前,先输出线程A、线程B的优先级,在默认情况下,新建线程的优先级都是0.5.程序中改变了线程A的优先级为0.0,这样线程A将会获得较少的执行机会:接下来程序将线程B的优先级设为1.0,这样线程B将会获得更多的执行机会.

     

         

     

  • 相关阅读:
    PHP 大小写转换、首字母大写、每个单词首字母大写转换相关函数
    【论文学习4】BiSample: Bidirectional Sampling for Handling Missing Data with Local Differential Privacy
    【论文学习3】Local Differential Privacy for Deep Learning
    【论文学习2】 Differential Privacy Reinforcement Learning
    深度学习中的优化算法
    Spatial crowdsourcing
    “pip install tensorflow ”出现错误
    python或pip'不是内部或外部命令”
    pip install torch出现错误
    打不开gitHub的解决方法
  • 原文地址:https://www.cnblogs.com/congli0220/p/4982204.html
Copyright © 2011-2022 走看看