GCD使用

GCD

简介:

1> iOS和OS X的核心是XNU内核,GCD是基于XNU内核实现的

2> GCD的API全部在libdispatch库中

3> GCD的底层实现主要有Dispatch Queue和Dispatch Source

Dispatch Queue:管理block(操作)

Dispatch Source:处理事件

一.并发串行,同步异步

1.GCD是面向任务和队列进行开发的,不用再关注线程这个概念.

2.GCD中有两个重要的概念:队列和任务

2.1队列决定了任务的执行方式,并发还是串行.

2.1.1并发:多个任务同时执行

2.1.2串行:任务一个接一个执行

2.1.3并发和串行只是决定了任务的执行方式,和开不开线程没有半毛钱关系

2.2任务决定了具不具备开线程的能力,异步任务和同步任务.

2.2.1异步:具有开线程的能力,但具体开多少个子线程,不是由我们决定,是由系统根据任务的多少决定开几个子线程比较合适.

2.2.2同步:不具备开线程的能力,所有的任务都放在主线程执行.因为只有一个线程,也就没有了并发和串行的概念.同步任务全部都是串行的.

2.2.3.1同步(sync)和异步(async)是修饰任务的,决定了具不具备开线程的能力

2.2.3.2并发和串行是修饰队列的,决定了队列中的任务是一起执行还是一个接着一个执行.

2.2.3.3而并发的前提需要有多个线程,只有异步才会创建多个线程,所以同步异步的优先级高于并发串行的优先级.

总结:

异步串行:

异步具备了开线程的能力,串行决定了任务一个接着一个执行.所以线程开多了也没什么卵用,系统只会开一条子线程,任务在这条子线程中一个接着一个执行.

异步并发:异步具备了开线程的能力,并发决定了子线程中的任务一起执行.所以系统分批开线程,每批开多条线程,多条线程一起执行线程中的任务.但每批具体开多少条线程是由系统决定,并不一定是有多少个任务就开多少个线程.线程开辟的数量(n)和任务的数量(m)成正相关,但并不是严格的一一对应.当开辟的线程数量(n)小于总的任务(m)的时候,前线程个数(n)个线程同时执行.而且当前边的某个线程执行完任务以后,这个线程死亡或者继续给它分配其他任务也是由系统说了算,我们无法控制.

同步串行:同步不具备开线程的能力,所以所有的任务都在主线程中执行.串行决定了任务一个接一个执行.最后的结果就是所有的任务都在子线程中循规蹈矩的一个接一个执行.

同步并发:同步不具备开线程的能力,所以所有的任务都在主线程中执行.并发决定了任务一起执行.但任务一起执行的前提是有多个线程,这里只有一个线程,所以并发不起来(同步异步的优先级高于并发串行的优先级).所以最后的结果还是所有的任务都在主线程中循规蹈矩的一个接一个执行.

二.队列

1.队列:GCD中一共有两个重要的概念:队列和任务.其中任务需要放在队列中才可能被执行.

1.1队列的分类:GCD中任务一共被分为5种:

high优先级的

default优先级的

low优先级的

backGround队列

主队列

1.1.1其中优先级高的里边的任务被执行的频率高一点点.

1.1.2一般自己创建的队列一般都用default类型.

1.2.1主队列中的任务都放在主线程中执行.

1.2.2其他的队列对应的都是子线程,他们中的任务要交给处于线程池中的线程执行.

1.2.2.1线程一共有5种状态:

①创建:创建完成,但没有开启,在内存中存在,但没有被放入线程池

②就绪:创建完成,已经开启,在内存中存在,已经被放入线程池

③被宠幸:创建完成,已经启动,在内存中存在,在线程池,并且CPU调度,队列把任务交给它执行

④阻塞:创建完成,已经启动,在内存中存在,被移出线程池,不能执行任务.

⑤销毁:不在线程池,也不在内存,被销毁,内存被回收

注:

1.这里说的内存是整个进程开辟的内存,进程是分配内存的最小单位,程序一启动,进程就划分一块内存,进程中所有的操作都在这块特定的内存中完成.

2.线程处在特定的内存中,并不一定就具有了执行任务的能力,要想执行任务,必须把它放入线程池中,放入线程池中的方式为start线程.

3.start线程以后,线程就具备了执行任务的能力,但具体执行不执行任务得有系统调度,系统调度队列把任务交给你执行你才会执行,否则就一直处于饥饿的就绪状态.

三.主队列

1.执行优先级

1.1非主队列:

其实任务放在队列中执行的整个逻辑过程是这样的:异步同步决定了是否具备开线程的能力,并发串行决定了任务在队列中如何执行.这个时候异步同步的优先级大于并发串行.

1.2主队列:如果是主队列的话,任务放在主队列,而主队列中的所有任务都需要放在主线程中执行,那么即使你开了子线程也是浪费,所以这个时候不管你是异步还是同步也不会开子线程.这个时候主队列的优先级高于异步同步.

1.3总结上面两点:

主队列优先级>异步同步>并发串行

2.同步主队列(死锁)

2.1同步:同步要求任务一个接一个执行,也就是说前一个任务没有执行完毕,后一个任务不能开始.后一个任务是在拿到前一个任务执行结果以后才开始的.

2.2主队列:任务放在主队列中执行,主队列中所有的任务都要放在主线程中执行.

2.3当调用同步主队列这个方法(

- (void)asyncMainQueue )的时候,( -

(void)asyncMainQueue )就放入主队列,只有拿到它的执行结果(也就是说只有这个方法执行完以后,程序执行到红色的}后),后放入这个队列中的任务(NSLog(@"-----下载图片1---%@", [NSThread

currentThread]);)才会执行.但-

(void)asyncMainQueue这个方法要想执行完毕的前提是(NSLog(@"-----下载图片1---%@", [NSThread

currentThread]);)必须执行完毕.这个时候就引起了死锁.

-

(void)asyncMainQueue

{

// 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)

dispatch_queue_t

queue = dispatch_get_main_queue();

// 2.添加 任务 到主队列中

异步 执行

dispatch_async(queue,

^{

NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

});

}

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

{

//    //创建一个并发队列

//

dispatch_queue_t queue  =

dispatch_queue_create("downLoad-queue", DISPATCH_QUEUE_CONCURRENT);

//创建一个串行队列

dispatch_queue_tqueue =dispatch_queue_create("queue",DISPATCH_QUEUE_SERIAL);

//创建一个异步函数,因为下载图片是耗时操作,所以放在子线程中

dispatch_async(queue, ^{

NSLog(@"%@", [NSThreadcurrentThread]);

//1.下载路径

NSURL*url = [NSURLURLWithString:@"http://img2.kwcdn.kuwo.cn/star/KuwoArtPic/2013/22/1396932137246_w.jpg"];

//2.把url数据转化成2进制数据

NSData*data = [NSDatadataWithContentsOfURL:url];

//3.把2进制数据转化成图片

UIImage*image = [UIImageimageWithData:data];

//4.刷新UI

/**这里为什么没有死锁呢?

*一定要抓住本质:

死锁:主队列+同步而不是同步+主队列

只有在主队列的任务中,再次添加同步任务才会导致死锁.这里主队列的任务指的是红色的代码块,而紫色的函数并不在主队列中,它还在子线程中.如果在红色的代码块中又创建了同步任务,那么就会导致死锁.

*/

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"%@", [NSThread

currentThread]);

//赋值

[self._imageBtn setBackgroundImage:image

forState:UIControlStateNormal];

});

});

}

补充:

线程间通信:

1.线程间通信是通过队列完成的

2.子线程是放在线程池中的,主线程不放在线程池,所以主线程和子线程之间无法之间连接起来.只能通过队列.

总结:GCD中两个概念:用block封装好任务,把它放在队列中,它会自动执行.

1.队列:存放任务的

2.任务:用block来封装

*/

/**

*  GCD作用:

延时操作:

下边四种方法都可以进行延时操作,但最后一种会卡死主线程,所以不推荐使用;

第一种,在什么队列中调用perform方法就在什么队列中执行,不能控制.

推荐使用GCD:既不会卡死主线程,而且可以控制在主线程还是子线程执行

①如果放主队列(dispatch_get_main_queue()),就在主队列中执行

dispatc_after(dispatch_time(DISPATCH_TIME_NOW,

(int64_t)(3 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

NSLog(@"这里的任务会在三秒中以后执行,并且在主队列中执行");

});

②如果放全局并发队列就在子线程中执行

1.1不会卡住主线程:在主线程执行

[self performSelector:@selector(download:)

withObject:@"http://baidu.com" afterDelay:3];

1.2不会卡主主线程:在主线程执行

dispatc_after(dispatch_time(DISPATCH_TIME_NOW,

(int64_t)(3 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

NSLog(@"这里的任务会在三秒中以后执行,并且在主队列中执行");

});

1.3不会卡主主线程:在子线程执行,会创建子线程

dispatch_queue_t queue =

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatc_after(dispatch_time(DISPATCH_TIME_NOW,

(int64_t)(3 * NSEC_PER_SEC)),queue, ^{

NSLog(@"这里的任务会在三秒中以后执行,并且在子线程中执行");

});

1.4会卡住主线程:在主线程中执行

[NSThread

sleepForTimeInterval:3];

NSLog(@"这里的任务会在三秒中以后执行,在主线程中执行,并且会卡住主线程");

*/

- (void)viewDidLoad

{

[superviewDidLoad];

[selfsetupThread];

}

- (void)setupThread

{

dispatch_queue_tmainQueue =dispatch_get_main_queue();

dispatch_queue_tglobalQueue =dispatch_get_global_queue(0,0);

dispatch_sync(globalQueue, ^{

NSLog(@"2 ------%@", [NSThreadcurrentThread]);

});

dispatch_async(mainQueue, ^{

NSLog(@"4------%@", [NSThreadcurrentThread]);

});

dispatch_async(globalQueue, ^{

NSLog(@"3------%@", [NSThreadcurrentThread]);

});

dispatch_async(globalQueue, ^{

NSLog(@"5------%@", [NSThreadcurrentThread]);

});

NSLog(@"1------%@", [NSThreadcurrentThread]);

dispatch_async(mainQueue, ^{

NSLog(@"5------%@", [NSThreadcurrentThread]);

});

dispatch_async(mainQueue, ^{

NSLog(@"6------%@", [NSThreadcurrentThread]);

});

[selfperformSelectorInBackground:@selector(run)withObject:nil];

NSLog(@"8------%@", [NSThreadcurrentThread]);

}

- (void)run{

NSLog(@"7------%@", [NSThreadcurrentThread]);

}

1.首先执行的是sync函数并发队列或者默认情况,这两种情况写在前面的先执行

2.接着执行async并发队列

3.最后执行async串行队列

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容