单词:thread 英 θred:n 线、思路、vt 穿过、vi 穿透过

一、    进程、线程

进程:正在进行中的程序被称为进程,负责程序运行的内存分配,每一个进程都有自己独立的虚拟内存空间

线程:线程是进程中一个独立的执行路径(控制单元),一个进程中至少包含一条线程,即主线程(UI操作),可以将耗时的执行路径(如网络请求)放在其他线程中执行,线程不能被杀掉,但是可以暂停/休眠一条线程。

创建线程的目的:开启一条新的执行路径,运行指定的代码,与主线程中的代码实现同时运行

多线程的优势:充分发挥多核处理器优势,将不同线程任务分配给不同的处理器,真正进入"并行运算"状态;将耗时的任务分配到其他线程执行,由主线程负责统一更新界面会使应用程序更加流畅,用户体验更好;当硬件处理器的数量增加,程序会运行更快,而程序无需做任何调整.。

弊端:新建线程会消耗内存空间和CPU时间,线程太多会降低系统的运行性能

二、    NSThread

优点:NSThread 比其他两个轻量级

缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

1、获取当前线程
NSLog(@"%@",[NSThread currentThread]);//获取当前线程,当打印的number等于1时,代表当前是主线程,大于1代表子线程
2、创建子线程方式(两种方法)
1)显式创建方式,需要手动开启线程。 最后的object代表线程触发方法时传递的参数,注意,有且只有一个参数
thread = [[NSThreadalloc] initWithTarget:selfselector:@selector(run1:) object:@"123"];
    thread.name = @"123";//给线程起个名字
    [thread start];//开启线程
2)隐式创建方式,不需要手动开启
[NSThread detachNewThreadSelector:@selector(run2) toTarget:self withObject:nil];

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

3、线程间通讯

回到主线程:    [self performSelectorOnMainThread:@selector(testMain:) withObject:nil waitUntilDone:YES];// waitUntilDone是指是否等到主线程把方法执行完了,这个performSelector方法才返回。

在指定线程上执行操作:[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];

在本线程执行:    [self performSelector:@selector(run) withObject:nil];

4、实现方法
1) [NSThread sleepForTimeInterval:3];//让调用该方法的线程睡一会,参数代表秒数
2)  NSRunLoop *r = [NSRunLoop currentRunLoop];//获取当前线程的runloop
3)  [self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:NO];//跳入主线程的方法,第一个参数代表要调用的方法,第二个参数代表传的值,第三个参数代表是否等待此操作完成后再继续往下执行
4) [self performSelector:@selector(test) withObject:nil];//在当前线程执行另外一个方法
5) [self performSelector:@selector(test) withObject:nil afterDelay:3];//延迟调用
6) NSDate *date = [NSDate dateWithTimeInterval:2 sinceDate:[NSDate date]];

[NSThread sleepUntilDate:date];//以当前时间为标准,延迟到某个时间再执行该线程操作

7) 获取主线程:    NSThread *main = [NSThread mainThread];

8) 获取当前线程:    NSThread *current = [NSThread currentThread];

9) 结束线程:[NSThread exit];//当前线程方法中使用

[thread cancel];//主线程中使用

5、具体代码如下:
#import "ViewController.h"
@interface ViewController (){
    NSThread *thread;
    BOOL    _isEnd;//线程终止的标识
}
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    _isEnd = NO;
    NSLog(@"%@",[NSThread currentThread]);//获取当前线程,当打印的number等于1时,代表当前是主线程,大于1代表子线程
    //*子线程创建方式1: 最后的object代表线程触发方法时传递的参数,注意,有且只有一个参数
    thread = [[NSThread alloc] initWithTarget:self selector:@selector(run1:) object:@"123"];
    thread.name = @"123";//给线程起个名字
    [thread start];//开启线程,只有显式的创建方式,需要手动开启、
    //*子线程创建方式2:
    [NSThread detachNewThreadSelector:@selector(run2) toTarget:self withObject:nil];//隐式创建,不需要手动开启
}
-(void)run1:(NSString *)str{
   // [NSThread sleepForTimeInterval:3];//让调用该方法的线程睡一会,参数代表秒数
    NSLog(@"子线程:%@",[NSThread currentThread]);
    NSRunLoop *r = [NSRunLoop currentRunLoop];//获取当前线程的runloop
    //判断当前线程是否需要循环(线程继续存活)
    while (!_isEnd) {
        [r runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];//runMode 第一个参数代表消息方式,默认写NSDefaultRunLoopMode,第二个参数代表结束时间,一般给distantFuture,代表不可达到的未来某个时间
    }
    NSLog(@"销毁");
}
-(void)run2{
    NSLog(@"子线程2:%@",[NSThread currentThread]);
//*    [self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:NO];//跳入主线程的方法,第一个参数代表要调用的方法,第二个参数代表传的值,第三个参数代表是否等待此操作完成后再继续往下执行
   
 //*   [self performSelector:@selector(test) withObject:nil];//在当前线程执行另外一个方法
 //*延迟调用    [self performSelector:<#(nonnull SEL)#> withObject:<#(nullable id)#> afterDelay:<#(NSTimeInterval)#>] 
    [self performSelector:@selector(run3) onThread:thread withObject:nil waitUntilDone:NO];//在某个线程中执行某个方法 
    NSLog(@"其他");
}
-(void)run3{
    _isEnd = YES;//方法执行结束后将线程结束标识置为YES
    NSLog(@"-----");
}
-(void)test{
    NSLog(@"主线程方法%@",[NSThread currentThread]);
}
 

三、    Cocoa NSOperation

优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。

NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作。

NSOperation本身是抽象基类,因此必须使用它的子类,使用NSOperation子类的方式有2种:一种是用定义好的两个子类:NSInvocationOperation 和 NSBlockOperation,另一种是自定义子类继承NSOperation,实现内部相应的方法

1、       NSOperation的作用:配合使用NSOperation和NSOperationQueue也能实现多线程编程取消操作

2、       NSOperation和NSOperationQueue实现多线程的具体步骤:

先将需要执行的操作封装到一个NSOperation对象中

然后将NSOperation对象添加到NSOperationQueue中

系统会⾃动将NSOperationQueue中的NSOperation取出来

将取出的NSOperation封装的操作放到⼀条新线程中执⾏

2、创建操作对象,封装要执行的任务
//NSInvocationOperation   封装操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run1) object:nil];
 
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run1) object:nil];
3、执行操作
    [operation start];
    [operation1 start];
注意:操作对象默认在主线程中执行,只有添加到队列中才会开启新的线程。即默认情况下,如果操作没有放到队列queue中,都是同步执行。只有将NSOperation放到一个
4、NSBlockOperation创建操作对象
    NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"block操作:%@",[NSThread currentThread]);
    }];
    //在NSBlockOperation对象中添加一个操作,如果NSBlockOperation对象包含了多个操作,有一个是在主线中一行,其他均在子线程中执行
5、添加操作(注意添加要放在start之前)
    [block addExecutionBlock:^{
        NSLog(@"block操作2:%@",[NSThread currentThread]);
    }];
    [block addExecutionBlock:^{
       NSLog(@"block操作3:%@",[NSThread currentThread]);
    }];
    [block addExecutionBlock:^{
        NSLog(@"block操作4:%@",[NSThread currentThread]);
    }];
    6、执行操作
  [block start ];//注意添加要放在start之前
   
    7、NSOperationQueue:创建队列:将操作放入队列(主队列除外),默认在子线程中执行,且不需要手动start
1)NSOperationQueue的作⽤:NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作到NSOperationQueue中,自动执行操作,自动开启线程
2)创建NSOperationQueue 
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    NSInvocationOperation *ioperation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run2) object:nil];
8、把操作添加到队列中
   1)第一种:添加之前创建的
  [queue addOperation:ioperation];
   2)第二种:添加的时候创建
注意:使用NSOperationQueue时,无需start
  [queue addOperationWithBlock:^{
        NSLog(@"block操作队列:%@",[NSThread currentThread]);
    }];
9、事件的实现
-(void)run1{
    NSLog(@"执行操作:%@",[NSThread currentThread]);
}
-(void)run2{
    NSLog(@"队列中执行:%@",[NSThread currentThread]);
}
 
 
四、GCD 全称:Grand Central Dispatch
1、Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。在iOS4.0开始之后才能使用。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。
2、GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务
3、 GCD是基于C语言的。如果使用GCD,完全由系统管理线程,我们不需要编写线程代码。只需定义想要执行的任务,然后添加到适当的调度队列(dispatch queue)。GCD会负责创建线程和调度你的任务,系统直接提供线程管理
4、常用的方法dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 耗时的操作
        dispatch_async(dispatch_get_main_queue(), ^{
            // 更新界面
        });
});
dispatch_async开启一个异步操作,第一个参数是指定一个gcd队列,第二个参数是分配一个处理事物的程序块到该队列。
dispatch_get_global_queue(0, 0),指用了全局队列。
一般来说系统本身会有3个队列:global_queue、current_queue(废弃)和main_queue
获取一个全局队列是接受两个参数,第一个是我分配的事物处理程序块队列优先级。分高低和默认,0为默认2为高,-2为低
5、dispatch_group_async的使用
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成了。
1)创建一个组
    dispatch_group_t group = dispatch_group_create();
2)在一个组内提交一个代码块来执行。必须明确这个代码块属于哪个组,必须     在哪个派送队列上执行。
dispatch_group_async(group, queue, ^{
       NSLog(@"group1--%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"group2--%@",[NSThread currentThread]);    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"group3--%@",[NSThread currentThread]);    });
3)等待组中的任务执行完毕,回到主线程执行block回调
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"updateUi");
    });
6、dispatch_barrier_async
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
     //创建队列,第一个参数代表队列名,第二个代表串行还是并行:DISPATCH_QUEUE_SERIAL串行   DISPATCH_QUEUE_CONCURRENT 并行
  dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"dispatch_async1");
});
//上一步执行结束才执行这一步
    dispatch_barrier_async(queue, ^{
        NSLog(@"dispatch_barrier_async");
});
//执行完上一步才执行下一步
    dispatch_async(queue, ^{
        NSLog(@"dispatch_async3");
    });
7、dispatch_apply 
     它一般都是放在dispatch_async里面(异步)。
执行某个代码片段N次
  dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t index) {
            NSLog(@"%ld",index);
        }); 
    });
 
 
8、具体代码
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    UIImageView *imageview = [[UIImageView alloc]initWithFrame:CGRectMake(10, 30, 100, 100)];
    [self.view addSubview:imageview];
    UIImageView *imageview1 = [[UIImageView alloc]initWithFrame:CGRectMake(30, 150, 100, 100)];
    [self.view addSubview:imageview1];
   UIImageView *imageview2 = [[UIImageView alloc]initWithFrame:CGRectMake(30, 270, 100, 100)];
    [self.view addSubview:imageview2];
    UIImageView *imageview3 = [[UIImageView alloc]initWithFrame:CGRectMake(30, 390, 100, 100)];
    [self.view addSubview:imageview3];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //NSLog(@"耗时操作:%@",[NSThread currentThread]);   
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.yooyoo360.com/photo/2009-1-1/20090112132752467.jpg"]];
        UIImage *image = [UIImage imageWithData:data];
        //NSLog(@"---%@",image);
        //返回主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            //NSLog(@"更新UI:%@",[NSThread currentThread]);
            imageview.image = image;
        });   
    });
    //组
    //创建组,用于存放耗时操作
    dispatch_group_t group = dispatch_group_create();  
    __block UIImage *image,*image1,*image2,*image3;
    //将操作封装进组,第一个参数代表要存放操作的组名,第二个参数代表操作队列,block执行耗时操作
//在一个组内提交一个代码块来执行。必须明确这个代码块属于哪个组,必须在哪个派送队列上执行。
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic2.ooopic.com/10/81/58/62bOOOPICce.jpg"]];
        image1 = [UIImage imageWithData:data];
        //NSLog(@"==%@",image1);
    });
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.downsc.com/vector_pic/shiliang_iecool/5/3/b_img/14430.jpg"]];
        image2 = [UIImage imageWithData:data];
    });
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.downsc.com/vector_pic/shiliang_iecool/5/2/b_img/13788.jpg"]]; 
        image3 = [UIImage imageWithData:data];
        //NSLog(@"----%@",image); 
    });
    //监听一组操作,第一个参数代表要监听的组名,第二个参数代表一组操作完全结束后跳转到哪个队列,一般跳到主线程(dispatch_get_main_queue),block执行要进行的操作(一般用来更新UI),注意:此方法在组中的所有操作执行完毕后调用
//等待组中的任务执行完毕,回到主线程执行block回调
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        imageview.image = image;
        imageview1.image = image1;
        imageview2.image = image2;
        imageview3.image = image3;
    });
}
-(void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end
 

NSThread 子线程 Cocoa NSOperation GCD(Grand Central Dispatch) 多线程的更多相关文章

  1. GCD (Grand Central Dispatch) 笔记

    GCD (Grand Central Dispatch) 是Apple公司开发的一种技术,它旨在优化多核环境中的并发操作并取代传统多线程的编程模式. 在Mac OS X 10.6和IOS 4.0之后开 ...

  2. iOS开发-多线程之GCD(Grand Central Dispatch)

    Grand Central Dispatch(GCD)是一个强有力的方式取执行多线程任务,不管你在回调的时候是异步或者同步的,可以优化应用程序支持多核心处理器和其他的对称多处理系统的系统.开发使用的过 ...

  3. Multithreading annd Grand Central Dispatch on ios for Beginners Tutorial-多线程和GCD的入门教程

    原文链接:Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial Have you ever written a ...

  4. Grand Central Dispatch (GCD)

    Grand Central Dispatch (GCD) Reference Grand Central Dispatch (GCD) comprises language features, run ...

  5. IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习

    介绍:前面内容源自网络 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式 ...

  6. IOS学习之十七:Grand Central Dispatch(GCD)编程基础

    IOS学习之十七:Grand Central Dispatch(GCD)编程基础   有过编程经验的人,基本都会接触到多线程这块. 在java中以及Android开发中,大量的后台运行,异步消息队列, ...

  7. [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...

  8. iOS 多线程编程之Grand Central Dispatch(GCD)

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...

  9. iOS开发之四张图说明GCD(Grand Central Dispatch)附Test源码

    首先,先介绍几个概念:GCD,队列,串行,并行,同步,异步.                                                                       ...

随机推荐

  1. AngularJs + Web API 页面开发(一)

    AngularJS这个JS框架是个神马东东我也不太清楚,我也是初学者~~ AngularJS适用于single page App,单页面程序都是局部刷新的,这一点和Ajax有第一的区别,因为使用Aja ...

  2. Lucene教程(转)

    Lucene教程 1 lucene简介1.1 什么是lucene    Lucene是一个全文搜索框架,而不是应用产品.因此它并不像www.baidu.com 或者google Desktop那么拿来 ...

  3. c语言折半查找

    折半查找又称为二分查找,它的前提是线性表中的记录必须是有序的(通常从小到大有序),线性表必须采用顺序存储. 折半查找的基本思想是 : 在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等 ...

  4. 使用yield关键字让自定义集合实现foreach遍历

    一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...

  5. 关于C# DataTable 的一些操作

    经常操作DATATABLE  对于一些不需要再通过sql 来重复操作的   可以通过操作datatable来达到同样的效果 方法一: 也是广为人知的一种: YourDataTable.Columns. ...

  6. Twitter的分布式自增ID算法snowflake (Java版)

    概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种 ...

  7. JavaScript 常用函数总结

    javascript函数:  ·常规函数  ·数组函数  ·日期函数  ·数学函数  ·字符串函数 .cookie函数 1.常规函数 javascript常规函数包括以下9个函数:  (1)alert ...

  8. shell 环境初始化顺序

    登陆shell 的执行顺序 /etc/profile /etc/profile.d/file /etc/bashrc .bashrc .bash_profile 非登录shell 的执行顺序, 例如: ...

  9. textField和textView限制输入条件

    以下两法方法都是实现textfield和textView的代理方法  需要先遵循代理 一:textField限制只能输入数字和小数点 且小数点后只能保留两位 小数点前最多5位 - (BOOL)text ...

  10. 《Linux 多线程服务端编程:使用 muduo C++ 网络库》电子版上市

    <Linux 多线程服务端编程:使用 muduo C++ 网络库> 电子版已在京东和亚马逊上市销售. 京东购买地址:http://e.jd.com/30149978.html 亚马逊Kin ...