代码拉取完成,页面将自动刷新
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>
OC 多线程之 GCD知识从基础到进阶 (1) - kaelinda
</title>
<link href="atom.xml" rel="alternate" title="kaelinda" type="application/atom+xml">
<link rel="stylesheet" href="asset/css/foundation.min.css" />
<link rel="stylesheet" href="asset/css/docs.css" />
<script src="asset/js/vendor/modernizr.js"></script>
<script src="asset/js/vendor/jquery.js"></script>
<script src="asset/highlightjs/highlight.pack.js"></script>
<link href="asset/highlightjs/styles/github.css" media="screen, projection" rel="stylesheet" type="text/css">
<script>hljs.initHighlightingOnLoad();</script>
<script type="text/javascript">
function before_search(){
var searchVal = 'site:kaelinda.top ' + document.getElementById('search_input').value;
document.getElementById('search_q').value = searchVal;
return true;
}
</script>
</head>
<body class="antialiased hide-extras">
<div class="marketing off-canvas-wrap" data-offcanvas>
<div class="inner-wrap">
<nav class="top-bar docs-bar hide-for-small" data-topbar>
<section class="top-bar-section">
<div class="row">
<div style="position: relative;width:100%;"><div style="position: absolute; width:100%;">
<ul id="main-menu" class="left">
<li id=""><a target="_self" href="index.html">最近更新</a></li>
<li id=""><a target="_self" href="archives.html">归档目录</a></li>
<li id="ios.css"><a target="_self" href="ios.html">iOS</a></li>
<li id="swift.css"><a target="_self" href="swift.html">Swift</a></li>
<li id="reactnative.css"><a target="_self" href="reactnative.html">RN</a></li>
<li id="js.css"><a target="_self" href="js.html">JS</a></li>
<li id="shell.css"><a target="_self" href="shell.html">shell</a></li>
<li id="coding.css"><a target="_self" href="coding.html">编程</a></li>
<li id="live.css"><a target="_self" href="live.html">随笔</a></li>
<li id="app.css"><a target="_blank" href="app.html">APP推荐</a></li>
</ul>
<ul class="right" id="search-wrap">
<li>
<form target="_blank" onsubmit="return before_search();" action="http://google.com/search" method="get">
<input type="hidden" id="search_q" name="q" value="" />
<input tabindex="1" type="search" id="search_input" placeholder="Search"/>
</form>
</li>
</ul>
</div></div>
</div>
</section>
</nav>
<nav class="tab-bar show-for-small">
<a href="javascript:void(0)" class="left-off-canvas-toggle menu-icon">
<span> kaelinda</span>
</a>
</nav>
<aside class="left-off-canvas-menu">
<ul class="off-canvas-list">
<li><a target="_self" href="index.html">最近更新</a></li>
<li><a target="_self" href="archives.html">归档目录</a></li>
<li><a target="_self" href="ios.html">iOS</a></li>
<li><a target="_self" href="swift.html">Swift</a></li>
<li><a target="_self" href="reactnative.html">RN</a></li>
<li><a target="_self" href="js.html">JS</a></li>
<li><a target="_self" href="shell.html">shell</a></li>
<li><a target="_self" href="coding.html">编程</a></li>
<li><a target="_self" href="live.html">随笔</a></li>
<li><a target="_blank" href="app.html">APP推荐</a></li>
<li><label>Categories</label></li>
<li><a href="reactnative.html">React-Native</a></li>
<li><a href="ios.html">iOS</a></li>
<li><a href="app.html">MacAPP</a></li>
<li><a href="swift.html">Swift</a></li>
<li><a href="js.html">JavaScript</a></li>
<li><a href="vue.html">Vue</a></li>
<li><a href="shell.html">shell</a></li>
<li><a href="%E7%BD%91%E7%BB%9C.html">网络</a></li>
</ul>
</aside>
<a class="exit-off-canvas" href="#"></a>
<section id="main-content" role="main" class="scroll-container">
<script type="text/javascript">
$(function(){
$('#menu_item_index').addClass('is_active');
});
</script>
<div class="row">
<div class="large-8 medium-8 columns">
<div class="markdown-body article-wrap">
<div class="article">
<h1>OC 多线程之 GCD知识从基础到进阶 (1)</h1>
<div class="read-more clearfix">
<span class="date">2018/5/12</span>
<span>posted in </span>
<span class="posted-in"><a href='ios.html'>iOS</a></span>
<span class="comments">
</span>
</div>
</div><!-- article -->
<div class="article-content">
<h2 id="toc_0">概念认知</h2>
<p>基本概念:</p>
<ul>
<li><p>GCD 全称 (Grand Center Dispatch),翻译成通俗中文“牛B的中心调度机制”</p></li>
<li><p>线程:执行任务调度的最小单位</p></li>
<li><p>任务:就是一段代码,GCD中就是block中的内容。执行任务有两种方式:同步执行(sync)和异步执行(async)。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力</p></li>
<li><p>队列:用来存放任务的线性结构,采用 FIFO(先进先出)的原则。</p></li>
</ul>
<span id="more"></span><!-- more -->
<p>进阶概念:</p>
<ul>
<li>同步:
<ul>
<li>同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行后续任务。</li>
<li>只能在当前线程中执行任务,不具备开启新线程的能力。<br/></li>
</ul></li>
<li><p>异步:</p>
<ul>
<li>异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。</li>
<li>可以在新的线程中执行任务,具备开启新线程的能力。</li>
</ul></li>
<li><p>串行队列: 队列中的任务 按添加顺序开始执行</p></li>
<li><p>并发队列: 队列中的任务可同时开始执行,可以开辟多个线程</p></li>
<li><p>主队列(等待主线程内的任务完成之后再利用主线程执行任务)</p></li>
<li><p>全局并发队列:本质上就是一个apple默认的并发队列</p></li>
</ul>
<h2 id="toc_1">GCD 使用步骤</h2>
<ul>
<li><p>创建队列:</p>
<pre><code class="language-text">// 串行队列的创建方法
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_SERIAL);<br/>
// 并发队列的创建方法<br/>
dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);<br/>
// 主队列的获取方法<br/>
dispatch_queue_t queue = dispatch_get_main_queue();<br/>
// 全局并发队列的获取方法<br/>
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
</code></pre></li>
<li><p>创建任务:</p>
<pre><code class="language-text">// 同步执行任务创建方法
dispatch_sync(queue, ^{<br/>
// 这里放同步执行任务代码<br/>
});<br/>
// 异步执行任务创建方法<br/>
dispatch_async(queue, ^{<br/>
// 这里放异步执行任务代码<br/>
});
</code></pre></li>
</ul>
<h2 id="toc_2">串行并发队列 + 同步异步组合</h2>
<blockquote>
<p>1.同步执行 + 并发队列<br/>
2.异步执行 + 并发队列<br/>
3.同步执行 + 串行队列<br/>
4.异步执行 + 串行队列<br/>
5.同步执行 + 主队列<br/>
6.异步执行 + 主队列</p>
</blockquote>
<p>各种组合:<br/>
<img src="http://cc.cocimg.com/api/uploads/20161030/1477828129712413.png" alt="串行并发队列+同步异步组合"/></p>
<p>问题:</p>
<ul>
<li><p>死锁:在<code>主线程</code>用<code>主队列</code>执行<code>同步任务</code>就会造成线程死锁。</p></li>
<li><p>主队列中的任务一定是在主线程中执行的</p></li>
<li><p>全局并发队列中的任务可以开辟新线程,但不一定会去开辟</p></li>
</ul>
<h2 id="toc_3">GCD 线程间通信</h2>
<pre><code class="language-text">// GCD的线程间的通信 : 常用代码
- (void)GCDDemo
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"正在努力下载... %@",[NSThread currentThread]);
// 如果下载结束回到主线程更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"下载完成,正在更新UI... %@",[NSThread currentThread]);
});
});
}
</code></pre>
<h2 id="toc_4">GCD 的其他方法</h2>
<h3 id="toc_5">GCD 栅栏方法:dispatch_barrier_async</h3>
<p>对于栅栏方法的理解,我觉得下面的图片很形象:<br/>
<img src="https://upload-images.jianshu.io/upload_images/1877784-4d6d77fafd3ad007.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700" alt=""/></p>
<pre><code class="language-text">dispatch_queue_t queue = dispatch_queue_create("net.bujige.testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_barrier_async(queue, ^{
// 追加任务 barrier
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"barrier---%@",[NSThread currentThread]);// 打印当前线程
}
});
dispatch_async(queue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
</code></pre>
<blockquote>
<p>虽然是异步任务 栅栏也能把这两个任务给有先后顺序的隔离开来。</p>
</blockquote>
<h3 id="toc_6">GCD 延时执行方法:dispatch_after</h3>
<blockquote>
<p>这里需要注意的是,延迟的时间是指的 延迟将任务添加到队列中。所以这个时间并不是特别准确的</p>
</blockquote>
<pre><code class="language-text">/**
* 延时执行方法 dispatch_after
*/
- (void)after {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"asyncMain---begin");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2.0秒后异步追加任务代码到主队列,并开始执行
NSLog(@"after---%@",[NSThread currentThread]); // 打印当前线程
});
}
</code></pre>
<h3 id="toc_7">GCD 一次性代码(只执行一次):dispatch_once</h3>
<pre><code class="language-text"> static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行1次的代码(这里面默认是线程安全的)
});
</code></pre>
<h3 id="toc_8">GCD 快速迭代方法:dispatch_apply</h3>
<pre><code class="language-text">dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"apply---begin");
dispatch_apply(6, queue, ^(size_t index) {
NSLog(@"%zd---%@",index, [NSThread currentThread]);
});
NSLog(@"apply---end");
</code></pre>
<h3 id="toc_9">GCD 队列组:dispatch_group</h3>
<pre><code class="language-text">NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"group---begin");
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的异步任务1、任务2都执行完毕后,回到主线程执行下边任务
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
NSLog(@"group---end");
});
</code></pre>
<h3 id="toc_10">GCD队列组监听:dispatch_group_notify</h3>
<pre><code class="language-text"> /*
* 业务异步串行执行,用GCD实现的四种方式
* 1、dispatch_group_notify(group, queue, ^{ });
* 2、dispatch_group_async(group, backQueue, ^{ });
* 3、dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 会有线程等待阻塞当前线程
* 4、信号量 = 0 实现;会有线程等待阻塞当前线程
*/
// 被监听的group
dispatch_group_t group = dispatch_group_create();
// 将要执行后续block代码的队列
dispatch_queue_t queue = dispatch_get_main_queue();
// ----------------- 监听group执行完毕 后,在queue队列执行block代码
dispatch_group_notify(group, queue, ^{
// 任务代码
});
// ---------------- 全局并发队列
dispatch_queue_t backQueue = dispatch_get_global_queue(0, 0);
// 向group中添加 在某个队列中执行的任务
dispatch_group_async(group, backQueue, ^{
// 追加的任务
});
/*
* 监听group执行完毕 之后在某个队列中执行某个任务
* 跟 向group中追加某个队列中执行的任务 也有类似作用,但是group不会有线程等待,只是会造成先后执行的效果,但是不会有线程等待
*/
// ------------ 在此处等待group中的任务执行完毕 然后 执行wait后面的代码,线程等待会阻塞当前线程
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// 创建信号量 初始信号量0 线程等待
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// 主队列中执行异步任务
dispatch_async(queue, ^{
// 信号量+1
dispatch_semaphore_signal(semaphore);
});
// 信号量不为0时候-1,信号量=0时候线程等待
// 异步任务异步执行后 直接带了wait,信号量=0 ,线程等待,等异步任务完毕时 信号量+1 不为零,此时线程不再等待,开始执行下面代码,会阻塞当前线程;
dispatch_semaphore_wait(semaphore, 1);
/*
* semaphore = 0 时候 dispatch_semaphore_wait 等待信号量!=0,
* 跟 dispatch_group_wait 等待group执行完毕 有一点相似。
*/
</code></pre>
<h3 id="toc_11">GCD中任务增删:dispatch_group_enter、dispatch_group_leave</h3>
<pre><code class="language-text">// 向任务组添加任务
dispatch_group_enter(group);
// 将要添加的任务
dispatch_async(queue, ^{
// 追加任务1
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
// 成对出现 任务组任务执行完毕 撤销任务
dispatch_group_leave(group);
});
// 等待group五秒钟
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC)));
// 要么五秒内执行完毕走到这里;要么五秒后超时,group还未执行完 就走到了这里
NSLog(@"等待之后");
// 如果只有enter 没有leave那么线程会一直存在 等待group执行完毕
</code></pre>
<h3 id="toc_12">GCD信号量:dispatch_semaphore_t</h3>
<pre><code class="language-text">
-(void)semaphoreLockTest{
dispatch_semaphore_t semaphoreLock = dispatch_semaphore_create(1);
// 创建两个购票的串行队列
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL);
__weak typeof(&*self)weakSelf = self;
// 第一个购票队列
dispatch_async(queue1, ^{
[weakSelf semaphoreGetTicket:semaphoreLock];
});
// 第二个购票队列
dispatch_async(queue2, ^{
[weakSelf semaphoreGetTicket:semaphoreLock];
});
}
-(void)semaphoreGetTicket:(dispatch_semaphore_t)semaphore{
while (1) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (YES) {
// 有票
// 模拟购票延时
[NSThread sleepForTimeInterval:0.2];
// 相当于解锁
dispatch_semaphore_signal(semaphore);
}else{
// 无票
// 相当于解锁
dispatch_semaphore_signal(semaphore);
break;
}
}
}
</code></pre>
<h2 id="toc_13">线程锁</h2>
<p><a href="https://www.jianshu.com/p/35dd92bcfe8c">iOS多线程-各种线程锁的简单介绍</a></p>
<hr/>
<p>本文参考文章:</p>
<ul>
<li><a href="https://www.jianshu.com/p/2d57c72016c6">iOS多线程:『GCD』详尽总结</a></li>
<li><a href="http://www.cocoachina.com/ios/20161031/17887.html">iOS-图文表并茂,手把手教你GCD</a></li>
</ul>
</div>
<div class="row">
<div class="large-6 columns">
<p class="text-left" style="padding:15px 0px;">
<a href="15268827199184.html"
title="Previous Post: NSURLRequest">« NSURLRequest</a>
</p>
</div>
<div class="large-6 columns">
<p class="text-right" style="padding:15px 0px;">
<a href="15257437237715.html"
title="Next Post: OC中的各种遍历">OC中的各种遍历 »</a>
</p>
</div>
</div>
<div class="comments-wrap">
<div class="share-comments">
</div>
</div>
</div><!-- article-wrap -->
</div><!-- large 8 -->
<div class="large-4 medium-4 columns">
<div class="hide-for-small">
<div id="sidebar" class="sidebar">
<div id="site-info" class="site-info">
<div class="site-a-logo"><img src="https://ws1.sinaimg.cn/large/006tNc79ly1fmpk9088gsj30sg0sgn33.jpg" /></div>
<h1>kaelinda</h1>
<div class="site-des">倘若我心中的山水,你眼中能看到,我便一步一莲花祈祷</div>
<div class="social">
<a target="_blank" class="twitter" target="_blank" href="https://twitter.com/KaelLVLinda" title="Twitter">Twitter</a>
<a target="_blank" class="github" target="_blank" href="https://github.com/Kaelzzs" title="GitHub">GitHub</a>
<a target="_blank" class="email" href="mailto:zhouzuosong_kael@163.com" title="Email">Email</a>
<a target="_blank" class="rss" href="atom.xml" title="RSS">RSS</a>
</div>
</div>
<div id="site-categories" class="side-item ">
<div class="side-header">
<h2>Categories</h2>
</div>
<div class="side-content">
<p class="cat-list">
<a href="reactnative.html"><strong>React-Native</strong></a>
<a href="ios.html"><strong>iOS</strong></a>
<a href="app.html"><strong>MacAPP</strong></a>
<a href="swift.html"><strong>Swift</strong></a>
<a href="js.html"><strong>JavaScript</strong></a>
<a href="vue.html"><strong>Vue</strong></a>
<a href="shell.html"><strong>shell</strong></a>
<a href="%E7%BD%91%E7%BB%9C.html"><strong>网络</strong></a>
</p>
</div>
</div>
<div id="site-categories" class="side-item">
<div class="side-header">
<h2>Recent Posts</h2>
</div>
<div class="side-content">
<ul class="posts-list">
<li class="post">
<a href="15523077857608.html">OC中枚举写法 以及 字符串枚举探索</a>
</li>
<li class="post">
<a href="15522686353535.html">iOS 动画全解 (1)</a>
</li>
<li class="post">
<a href="15501356584731.html">UITableView顶部空白的几种解决办法</a>
</li>
<li class="post">
<a href="15488351784332.html">Objective-C中的字符串类型枚举 探索</a>
</li>
<li class="post">
<a href="15409691048860.html">【Swift笔记】引用计数</a>
</li>
</ul>
</div>
</div>
</div><!-- sidebar -->
</div><!-- hide for small -->
</div><!-- large 4 -->
</div><!-- row -->
<div class="page-bottom clearfix">
<div class="row">
<p class="copyright">Copyright © 2015
Powered by <a target="_blank" href="http://www.mweb.im">MWeb</a>,
Theme used <a target="_blank" href="http://github.com">GitHub CSS</a>.</p>
</div>
</div>
</section>
</div>
</div>
<script src="asset/js/foundation.min.js"></script>
<script>
$(document).foundation();
function fixSidebarHeight(){
var w1 = $('.markdown-body').height();
var w2 = $('#sidebar').height();
if (w1 > w2) { $('#sidebar').height(w1); };
}
$(function(){
fixSidebarHeight();
})
$(window).load(function(){
fixSidebarHeight();
});
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script><script type="text/x-mathjax-config">MathJax.Hub.Config({TeX: { equationNumbers: { autoNumber: "AMS" } }});</script>
</body>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。