多线程

来源:互联网 发布:针对淘宝店主调查问卷 编辑:程序博客网 时间:2024/06/10 05:56
多线程
1.线程与进程的区别:
  (1)进程是一个动态运行的程序 
      进程是资源分配(比如内存空间)的最小单位 
      world 文档可以同时创建多个 此时就创建了多个进程. 
      ios 的程序一般是单进程的
  (2)线程是CPU 调度和分派的基本单位  
      一个进程可以包含多个线程 而一个线程只能属于一个进程.
      一个进程至少包含一个线程 称为主线程
      线程共享进程的资源
  (3)进程又独立的内存空间,一个进程崩溃之后,在保护模式下不会对其他进程造成影响 ,而线                              程只是一个进程中的不同的执行路径. 
   (4)系统会为主线程分配1M的连续的栈空间(ios) 但在其他 windows 系统中是2M
   (5)多线程 主要是为了解决程序运行缓慢的问题 实现了程序的并发运行


2.什么时候需要使用多线程
  (1)需要进行大量的计算 
  (2)当读取硬盘数据的时候(访问耗时操作)
  (3)进行网络请求的时候

3.多线程中的几个概念
 (1).线程
 (2).任务 task    线程来执行 task
 面试题:
 (3)什么是线程同步:  同步是串行操作  异步是并发执行  
 (4)什么时候使用到线程同步: 当第二个线程的执行需要使用线程一的结果 此时需要用到线        程同步
 (5)如何实现线程同步 :建立一个 NSOperationQueue 将最大并发数量设置为1 就会实现线程同步  或者利用 GCD 中的串行队列  或者 使用 barrier

4.人为开辟多线程:  实现多线程 方法 一
  (1)NSObject 类 performSelectorInBackground:SEL withObject:(id)arg
  (2)NSThread 类 中 类方法 + isMainThread 用于判断是否是主线程[NSThread isMainThread]; 用于判断当前的代码段是否是在主线程中执行的
  (3)注意一点:UI 的刷新一定要在主线程里面执行  子线程刷新 UI会出现异常,刷新不了,或者延迟刷新
 (4)从主线程中跳出 进行刷新页面 在子线程中[self performSelectorOnMainThread:SEL withObject:(id)arg waitUntilDone:(BOOL)wait];
     当 wait 参数为 YES  那么 在主线程中完成刷新 子线程等待直到主线程完成操作 在向下继续执行
     当 wait 参数为 NO 那么子线程不需要等待主线程完成操作 就可以 直接向下继续执行
 (5) 如果在子线程里执行方法的时候,要在方法中添加一个自动释放池 因为 线程与线程之间是相互独立的 ,但是资源是共享的,共享堆空间 ,如果子线程里开辟了空间,没有释放 其他线程就无法使用这块已经开辟的空间 尤其是当子线程中又大量的便利构造器的时候
 (6)线程 共享堆空间 但是不共享栈空间  每个子线程默认的栈的大小是512k .主线程栈的大小是1M. 栈空间的大小必须为4k 的整数倍

5.实现多线程方法二: 使用 NSThread 类 
  [NSThread detachNewThreadSelector:SEL toTarget:(id)target withObject:(id)arg];
    (1) 线程分两种 脱离线程 和 非脱离线程
        脱离线程:执行完任务后,自动销毁的线程
        非脱离线程:执行完成任务后,不会被销毁的线程,可以后续执行别的任务 如:主线程
    (2) 以上两种方式建立的线程都是 脱离线程 一旦任务执行完成 线程就自动销毁
        如果要建立一个 非脱离线程 要与 RunLoop (NSRunLoop)配合使用 对任务进行轮询
        每一个线程都有一个 NSRunLoop 对象 ,但是默认这个 runLoop 是关闭的. 一旦这个runLoop 开启,你的线程          就会成为 非脱离线程 . runLoop 帮你轮询有没有新的任务分配到了这个线程里面
   (3) 通过 performSelector:(SEL) onThread:(NSThread *) withObject:(id) waitUntilDone:(BOOL) 为线程添加任务      (4)可以 控制线程 延迟执行的问题 创建一个线程 线程需要执行的任务是 self 的 aa 方法  
        NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(aa) object:nil];
       [thread start];
6.实现多线程方法三: NSOperationQueue   与 NSOperation(NSInvocationOperation  NSBlockOperation)
   创建一个操作对象NSInvocationOperation 或者 NSBlockOperation 的操作对象
   创建一个操作队列 NSOperationQueue  
   将操作对象放到操作队列中  放到队列中后 不需要人为的对操作队列中的对象进行调用  队列会自动对操作对象进行调用  只需要操作对象放到操作队列中 不需要认为的调用 start ,  queue会根据操作的排队情况 帮你自动调用 start 安排线程
  [queue  addOperation: invocationOp1];

7.实现多线程方法四: GCD
   (1)GCD 中基本概念:
      1.Queue 队列 dispatch Queue(分发队列) (存放若干个 task)
      2.Task 任务  (一个单独的方法或者代码段)
      3.Thread 线程 (queue 为了让 task 顺利执行 会为 task 开辟 thread)
     
     Task 是一个一个单独的任务(函数 方法 block)
     Queue 里存放的是一个或者多个 Task
     Thread 为了保证 Task能顺利执行,Queue 会开辟适当的 Thread ,在开辟的 Thread 里面执行 Task

     GCD 全称 Grand Central Dispatch   (可以理解为 线程调度 ) 
     GCD 中用到的都是 C 函数,效率高 安全性高 通信简单
     GCD 中的函数都是以 dispatch 开头
 
     (2) Queue 分为两种
           1.serialQueue(串行队列) 特点: 任务先进先出,排在最前面的任务先执行,执行完成之后,后面的任务才会开始执行. 即任务1先执行,任务1执行完成之后,任务2开始执行,任务2执行完毕之后,任务3才开始执行,任务3执行完毕之后 任务4...
           2.concurrentQueue (并行队列)  特点:任务先进先出 ,排在最前面的任务先开始执行 一旦开始,后面的任务就开始执行 (无需等待前一个任务执行完毕). 即:任务1先开始执行,无需等待任务1 完成,任务2就开始执行,无需等待任务2执行完毕,任务3就开始执行,无需等待任务3执行完毕 ,任务4..
           你把任务放在什么样的队列里,任务就会遵守这个队列的规
 (3)任务串行进行执行 : 
        方法一:使用系统自带的 mainQueue 系统自带的 mainQueue 是一个单例  mainQueue 只会为任务开辟一个线程(无论又多少个任务),并且这个线程是主线程.  这里设置主线程的主要原因就是为了进行线程之间的通信 因为有的操作不能在子线程中执行(比如 UI 刷新界面)       
        获取主队列:  dispatch_queue_t queue = dispatch_get_main_queue()
        向主队列中添加任务: dispatch_async(queue, ^{ NSLog(@"任务1 是否是主线程:%d  %@",[NSThread isMainThread],[NSThread currentThread]); });
        dispatch_async 表示的是异步执行任务(不需要等待 block 中的代码完成就可以向下继续执行)  同时会有一个与其相反的操作 即 dispatch_sync  即表示同步执行任务 (只有执行完成同步 block 中的代码之后 才会向下继续执行)
 
        方法二:自己创建一个 serialQueue 串行队列(自己创建的 serialQueue 也只为任务(无论又多少个任务)开启一个线程,这些线程在子线程里执行 既不会卡死主线程 也能实现线程的同步)
       dispatch_queue_t queue = dispatch_queue_create("com.lanou.mySerialQueue", DISPATCH_QUEUE_SERIAL);
       dispatch_async(queue, ^{
        NSLog(@"任务1 是否是主线程:%d  %@",[NSThread isMainThread],[NSThread currentThread]);
 });
      //注意只要使用 create 创建了 queue 就要 release 这个 queue
      dispatch_release(queue);
(4)任务并发执行  使用 concurrentQueue (两种方式获取并发队列)
     方法一:使用系统自带的 globalQueue (它是一个单例)
     dispathch_queue_ t queue = dispatch_qet_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
            第一个参数表示优先级 共有三中优先级 一般使用 default 的优先级
     dispatch_async(queue,^{
            NSLog(@"任务1 是否是主线程:%d  %@",[NSThread isMainThread],[NSThread currentThread]);
            //在主线程中刷新 UI 实现线程之间的通信
            //获取主线程
             dispatch_queue_t mainQueue = dispatch_get_main_queue()
            //在主线程中刷新 UI
            dispatch_async(mainQueue, ^{
            NSLog(@"刷新你的 UI”);
         });
    });

方法二: 自己创建并行队列
      dispatch_queue_t queue =  dispatch_queue_create("com.lanou.myserial", DISPATCH_QUEUE_CONCURRENT);

(5)上面的任务都是立即执行的 如果想让任务 延迟执行
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  //第一个参数表示从现在开始 延迟2秒执行
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{
              NSLog(@"延迟执行”);
    });
(6)让任务 重复执行 多次 (主要会配合数组使用 让数组中的数据循环执行)
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //重复执行
    //第一个参数表示 执行的次数
     NSArray *arr = @[@"红楼梦",@"水浒传",@"三国演义",@"西游记”];
     dispatch_apply([arr count], queue, ^(size_t index) {
            NSLog(@"执行次数%ld ,%@",index,arr[index]);
         });
   //注意的是 这里在队列中的执行显示结果的顺序是无序的 并且执行也是无序的 
   //这里的循环次数为 几次 就相当于 放了几个任务在队列中 每个任务之间是 并发执行的
(7) 添加有 group 标记的任务到队列可以不是同一个队列)
     dispatch_group_t group = dispatch_group_create();
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //通过group 表示将任务添加到 queue (queue 可以不一样 只需要 group 标记一样)中 并用 group 进行标记 group 一样的是一组
     //notify 表示执行完成 group 中的任务之后 才执行的任务(这个任务可以在任何队列中进行执行 比如可以在主队列)
     dispatch_group_async(group, queue, ^{
            NSLog(@"任务一”);
    });
    dispatch_group_notify(group, queue, ^{
          NSLog(@"走,出发”);
    });
    dispatch_group_async(group, queue, ^{
         NSLog(@"任务二”);
   });

(8)任务屏蔽 barrier
     //dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);         dispatch_queue_t queue1 = dispatch_queue_create("com.lanou.serialQueue", DISPATCH_QUEUE_CONCURRENT);
     //对一些其他的事物进行屏蔽 比如在写入文件的时候 屏蔽一切的读操作
        dispatch_async(queue1, ^{
                 NSLog(@"任务1 所有的男同学”);
        });
      //使用 barrier 表示前面的执行完  并且后面的不能执行 当前只执行 barrier中的任务
      //但是使用 barrier 时候的要使用自己 create 的队列 不能使用 globle 队列和 串行队列 否则 barrier功能就会等同于 dispatch_async 没有特别的意义
      dispatch_barrier_async(queue1, ^{
                NSLog(@"写入 男生 年龄20岁以上 月薪10000以上 籍贯河南所有男生”);
                NSLog(@"写入 男生 年龄21岁以上 月薪10000以上 籍贯河南所有男生”);
                NSLog(@"写入 男生 年龄22岁以上 月薪10000以上 籍贯河南所有男生");
        });
      dispatch_async(queue1, ^{
                 NSLog(@"任务2 年龄是20岁以上的同学”);
                 NSLog(@"任务2 年龄是21岁以上的同学”);
                 NSLog(@"任务2 年龄是22岁以上的同学");
         });
打印结果:

(9)关与 once 一段代码在整个程序的生命周期中只执行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
            NSLog(@"dispatch_once”);
     });
   //可以用于单例

(10) 关于串行与并发  同步与异步
     dispatch_queue_t queue = dispatch_queue_create("com.lanou", DISPATCH_QUEUE_CONCURRENT);
     //同步  只有执行完成同步block 中的代码 才向下继续执行
      dispatch_sync( queue, ^{
             for (int i =0; i<10; i++) {
                    NSLog(@"%d",i);
               }
         });
     NSLog(@"over”);
    //异步 不需要等待 完成 block 中的代码 就可以向下执行
       dispatch_async( queue, ^{
            for (int i =0; i<10; i++) {
                   NSLog(@"%d",i);
               }
        });
      NSLog(@"over”);
   

   关于串行与并行 串行操作:只建立一个线程(任务只能顺序执行) 而并行操作 是可以建立多个线程(任务可以并发执行)

   关于同步和异步 同步:只有执行完成一个任务才能进行下一个任务  异步:不用等待这个任务完成就可以开始继续向下执行


(11) 关于函数指针  


0 0
原创粉丝点击