美文网首页
多线程网络01

多线程网络01

作者: 努力爬行中的蜗牛 | 来源:发表于2019-11-27 17:23 被阅读0次
1 进程和线程

1.1 进程
进程是指在系统中正在运行的一个应用程序。
比如同时代开迅雷、Xcode、系统就会分别启动两个进程。

1.2 线程
一个进程要想执行任务,必须得有线程(每一个进程至少要有1条线程)。
一个进程的所有任务都在线程中执行。
1个线程里面的任务是串行执行的。
如果要在一个线程中执行多个任务,那么只能一个一个地按顺序执行这些任务。
也就是说,在同一个时间内,1个线程只能执行一个任务。

1.3 进程和线程的比较
线程是CPU调用的最小单位。
进程是CPU分配资源和调度的单位。
一个程序可以对应多个进程,一个进程中可以有多个线程,但至少要有一个线程。
同一个进程内的线程共享进程的资源。

2 多线程

2.1 多线程定义
1个进程可以开启多条线程,每条线程可以并行执行不同的任务。进程->车间 线程->车间工人

2.2 多线程原理
同一时间,CPU只能处理1条线程,只有1条线程在工作(单CPU)。
多线程并发执行,其实是CPU快速的在多个线程间调度(切换)。
如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象。

3 多线程在ios开发中的应用

3.1
一个iOS程序运行后,默认会开启1条线程,称为主线程或者UI线程

3.2 主线程的主要作用
显示、刷新UI界面
处理UI事件(比如点击事件、滚动事件、拖动事件等)

3.3 主线程的应用注意
不要将比较耗时的操作放到主线程中
耗时操作会卡主主线程,严重影响UI的流畅度。

4 iOS开发中多线程的实现方案
技术方案 简介 语言 线程生命周期 使用频率
pthread 一套通用的多变成api,适用于Unix、linux、windows等系统,跨平台、可移植,使用难度大 c 程序管理 几乎不用
NSThread 使用面向对象,简单易用,可以直接操作线程对象 OC 程序员管理 偶尔使用
GCD 旨在替代NSThread等线程技术,充分利用设备的多核 C 自动管理 经常使用
NSOperation 基于GCD(底层是GCD) OC 自动管理 经常使用
5 NSThread的基本使用

5.1 开启线程方法

// 需要手动启动线程
- (void)createNewThread1 {
    // 1. 创建线程
    /*
     第一个参数:目标对象 self
     第二个参数:方法选择器 调用的方法
     第三个参数: 前面调用方法需要传递的参数 nil
     */
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"ABC"];
    
    //2.启动线程
    [thread start];
}

// 分离子线程,自动启动线程
- (void)createNewThread2 {
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"--分离子线程--"];
}


// 开启一条后台线程
- (void)createNewThread3 {
    [self performSelectorInBackground:@selector(run:) withObject:@"开启后台线程"];
}

- (void)run:(NSString *)param {
    NSLog(@"---run----%@", [NSThread currentThread]);
}
6 线程的生命周期

线程的生命周期:当线程中的任务执行完毕后被释放掉。

7 线程的状态

新建线程(New)(放入可调度线程池)->就绪(Runable)->运行(Running)


001.png 002.png
8 多线程的安全隐患

8.1 资源共享问题
1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源。
比如多个线程访问同一个对象,同一个变量,同一个文件。
当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。

8.2 安全隐患解决-互斥锁


003.png
9 原子和非原子属性
004.png
10 线程间通信

10.1 线程间通信
在一个进程中,线程间往往不是孤立的,多个线程之间需要经常及进行通信

10.2 线程间通信的体现

  • 1个线程传递数据给另一个线程
  • 在一个线程中执行完特定任务后,转到另一个线程继续执行任务

10.3 线程间通信常用方法

[self performSelectorOnMainThread:(nonnull SEL) withObject:(nullable id) waitUntilDone:(BOOL)]
[self performSelector:(nonnull SEL) onThread:(nonnull NSThread *) withObject:(nullable id) waitUntilDone:(BOOL)]
Snip20191210_3.png Snip20191210_5.png
11 GCD基本概念

11.1 什么是GCD

  • 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器"
    纯C语言,提供了非常多强大额函数

  • GCD的优势
    GCD是苹果公司为多核的并行运算提供的解决方案
    GCD会自动利用更多的CPU内核
    GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
    程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

11.2 任务和队列

  • GCD中有2个核心概念
    任务:执行什么操作
    队列:用来存放任务

  • GCD的使用就2个步骤
    定制任务:确定要做的事
    将任务添加到队列中
    GCD会自动将队列中的任务取出,放到对应的线程中执行
    任务的取出遵循队列的FIFO原则:先进先出,后进后出

11.3 执行任务

  • GCD中有2个用来执行任务的常用函数
  • 用同步的方式执行任务
dispatch_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
  • 用异步的方式执行任务
dispatch_async(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
  • 同步和异步的区别
    同步:只能在当前的线程中执行任务,不具备开启新线程的能力
    异步:可以在新的线程中执行任务,具备开启新线程的能力

11.4 队列的类型

  • GCD的队列可以分为2中类型

  • 并发队列(Concurrent Dispatch Queue)
    可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
    并发功能只有在异步函数才有效

  • 串行队列(Serial Dispatch Queue)
    让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

  • 有4个术语比较容易混淆:同步、异步、并发、串行
    同步和异步的主要影响:能不能开启新的线程
    同步:只能在当前的线程中执行任务,不具备开启新线程的能力
    异步:可以在新的线程中执行任务,具备开启新线程的能力

  • 并发和串行主要影响:任务的执行方式
    并发:允许多个任务并发(同时执行)
    串行:一个任务执行完毕后,再执行下一个任务

12 GCD的基本使用
// 异步函数+并发队列:会开启多线线程,队列中的任务是并发执行的
- (void)asyncConcurrent {
    // 1. 创建队列
    /*
     第一个参数:c语言字符串,标签
     第二个参数:队列类型
     */
    //dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_CONCURRENT);
    // 获得全局并发队列
    /*
     第一个参数:优先级
     第二个参数:备用参数
     */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 2. 1>封装任务2>添加任务到队列中
    dispatch_async(queue, ^{
        NSLog(@"download1--%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"download2--%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"download3--%@",[NSThread currentThread]);
    });
}

// 异步函数+串行队列:会开启1条线程,队列里面的任务是串行执行的
- (void)asyncSerial {
    // 1. 创建队列
    /*
     第一个参数:c语言字符串,标签
     第二个参数:队列类型
     */
    dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_SERIAL);
    // 2. 1>封装任务2>添加任务到队列中
    dispatch_async(queue, ^{
        NSLog(@"download1--%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"download2--%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"download3--%@",[NSThread currentThread]);
    });
}

// 同步函数+并发队里:不会开启线程,队列里面的任务是串行执行
- (void)syncConcurrent {
    // 1. 创建队列
    /*
     第一个参数:c语言字符串,标签
     第二个参数:队列类型
     */
    dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_CONCURRENT);
    // 2. 1>封装任务2>添加任务到队列中
    dispatch_sync(queue, ^{
        NSLog(@"download1--%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"download2--%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"download3--%@",[NSThread currentThread]);
    });
}

// 同步函数+串行队里:不会开启线程,队列里面的任务是串行执行
- (void)syncSerial {
    // 1. 创建队列
    /*
     第一个参数:c语言字符串,标签
     第二个参数:队列类型
     */
    dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_SERIAL);
    // 2. 1>封装任务2>添加任务到队列中
    dispatch_sync(queue, ^{
        NSLog(@"download1--%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"download2--%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"download3--%@",[NSThread currentThread]);
    });
}
13 主队列的相关用法

13.1 串行队列
GCD获得串行队列2中途径

  • 使用dispatch_queue_create函数创建串行队列
  • 使用主队列(跟主线程相关连的队列)
    主队列是GCD自带的一种特殊的串行队列
    放在主队列中的任务,都会放在主线程中执行
    使用dispatch_get_main_queue()获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 异步函数+主队列:不会开启新的线程,所有任务都在主线程中串行执行
- (void)asyncMainQueue {
    // 获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    // 2. 1>封装任务2>添加任务到队列中
    dispatch_async(queue, ^{
        NSLog(@"download1--%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"download2--%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"download3--%@",[NSThread currentThread]);
    });
}

// 同步函数+主队列:死锁
- (void)syncMainQueue {
    // 获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    // 2. 1>封装任务2>添加任务到队列中
    dispatch_sync(queue, ^{
        NSLog(@"download1--%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"download2--%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"download3--%@",[NSThread currentThread]);
    });
}

注:主队列里面的任务,会放到主线程里面执行,当主线程有任务在执行的时候,主队列会等待主线程里面的任务执行完毕后,再执行主队列里面的任务

14 同步和异步函数的区别和总结

14.1 各种队列的执行效果

队列 并发队列 手动创建的串行队列 主队列
同步(sync) 没有开启新线程,串行执行任务 没有开启新线程,串行执行任务 死锁
异步(async) 有开启新线程,并发执行任务 有开启新线程,任务串行执行 没有开启新线程,串行执行任务
15 线程间通信
// 创建子线程
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURL *url = [NSURL URLWithString:@"http://hiphotos.baidu.com/bailiyu/pic/item/898e36836ca0dd9b6d81190a.jpg"];
        
        NSData *data = [NSData dataWithContentsOfURL:url];
        // 更新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = [UIImage imageWithData:data];
        });
    });
16 GCD常用函数

16.1 延迟执行

// 延迟执行
- (void)delay {
    // 方法1
    //[self performSelector:@selector(task) withObject:nil afterDelay:2];
    
    // 方法2
    //[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(task) userInfo:nil repeats:YES];
    
    // 方法3
    /*
     参数1:DISPATCH_TIME_NOW 从现在开始计算时间
     参数2:延迟时间  2.0 GCD单位时间:纳秒
     参数3:队列
     */
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@">>>:%@",[NSThread currentThread]);
    });
}

16.2 一次性代码

- (void)once {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
}

相关文章

  • 多线程网络01

    1 进程和线程 1.1 进程进程是指在系统中正在运行的一个应用程序。比如同时代开迅雷、Xcode、系统就会分别启动...

  • 01-多线程网络

    1.多线程的底层实现? 1>首先搞清楚什么是线程、什么是多线程 2> Mach是第一个以多线程方式处理任务的系统,...

  • 01-网络多线程基础

    1.网络多线程基础 1.1 学习多线程的目的 学习多线程最主要的目的是将耗时的操作放在后台处理,保证UI界面的正常...

  • iOS知识体系

    UI 网络 多线程

  • 多线程、网络-整理中

    多线程、网络-整理中

  • 01-关于多线程&网络

    1.多线程的底层实现? 1>首先搞清楚什么是线程、什么是多线程 2> Mach是第一个以多线程方式处理任务的系统,...

  • iOS多线程04-NSOperation实践

    推荐文章 iOS多线程01-介绍iOS多线程02-NSThread实践iOS多线程03-GCD实践iOS多线程04...

  • 多线程

    1.多线程技术01

  • python多线程基础

    多线程准备脚本test01 多线程准备脚本test02 多线程准备脚本test03 多线程准备脚本test04 1...

  • java多线程相关

    (一) 基础篇 01.Java多线程系列--“基础篇”01之 基本概念 02.Java多线程系列--“基础篇”02...

网友评论

      本文标题:多线程网络01

      本文链接:https://www.haomeiwen.com/subject/gkypwctx.html