1.进程与线程

  • 进程:

    1.进程是一个具有一定独立功能的程序关于某次数据集合的一次运行活动,它是操作系统分配资源的基本单元.

    2.进程是指在系统中正在运行的一个应用程序,就是一段程序的执行过程,我们可以理解为手机上的一个app.

    3.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内,拥有独立运行所需的全部资源

  • 线程

    1.程序执行流的最小单元,线程是进程中的一个实体.

    2.一个进程要想执行任务,必须至少有一条线程.应用程序启动的时候,系统会默认开启一条线程,也就是主线程

  • 进程和线程的关系

    1.线程是进程的执行单元,进程的所有任务都在线程中执行

    2.线程是 CPU 分配资源和调度的最小单位

    3.一个程序可以对应多个进程(多进程),一个进程中可有多个线程,但至少要有一条线程

    4.同一个进程内的线程共享进程资源

2.什么是多线程?

  • 多线程的实现原理:事实上,同一时间内单核的CPU只能执行一个线程,多线程是CPU快速的在多个线程之间进行切换(调度),造成了多个线程同时执行的假象。

  • 如果是多核CPU就真的可以同时处理多个线程了。

  • 多线程的目的是为了同步完成多项任务,通过提高系统的资源利用率来提高系统的效率。

3.多线程的优点和缺点

  • 优点:

    能适当提高程序的执行效率

    能适当提高资源利用率(CPU、内存利用率)

  • 缺点:

    开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能

    线程越多,CPU在调度线程上的开销就越大

    程序设计更加复杂:比如线程之间的通信、多线程的数据共享

4.多线程的 并行 和 并发 有什么区别?

  • 并行:充分利用计算机的多核,在多个线程上同步进行

  • 并发:在一条线程上通过快速切换,让人感觉在同步进行

5.iOS中实现多线程的几种方案,各自有什么特点?

  • NSThread 面向对象的,需要程序员手动创建线程,但不需要手动销毁。子线程间通信很难。

  • GCD c语言,充分利用了设备的多核,自动管理线程生命周期。比NSOperation效率更高。

  • NSOperation 基于gcd封装,更加面向对象,比gcd多了一些功能。

6.多个网络请求完成后执行下一步

  • 使用GCD的dispatch_group_t

    创建一个dispatch_group_t

    每次网络请求前先dispatch_group_enter,请求回调后再dispatch_group_leave,enter和leave必须配合使用,有几次enter就要有几次leave,否则group会一直存在。

    当所有enter的block都leave后,会执行dispatch_group_notify的block。

     
NSString *str = @"http://xxxx.com/";
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession]; dispatch_group_t downloadGroup = dispatch_group_create();
for (int i=0; i<10; i++) {
dispatch_group_enter(downloadGroup); NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%d---%d",i,i);
dispatch_group_leave(downloadGroup);
}];
[task resume];
} dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
NSLog(@"end");
});
  • 使用GCD的信号量dispatch_semaphore_t

    dispatch_semaphore信号量为基于计数器的一种多线程同步机制。如果semaphore计数大于等于1,计数-1,返回,程序继续运行。如果计数为0,则等待。dispatch_semaphore_signal(semaphore)为计数+1操作,dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)为设置等待时间,这里设置的等待时间是一直等待。

    创建semaphore为0,等待,等10个网络请求都完成了,dispatch_semaphore_signal(semaphore)为计数+1,然后计数-1返回

     
NSString *str = @"http://xxxx.com/";
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession]; dispatch_semaphore_t sem = dispatch_semaphore_create(0);
for (int i=0; i<10; i++) { NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%d---%d",i,i);
count++;
if (count==10) {
dispatch_semaphore_signal(sem);
count = 0;
}
}];
[task resume];
}
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"end");
});

7.多个网络请求顺序执行后执行下一步

  • 使用信号量semaphore

    每一次遍历,都让其dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER),这个时候线程会等待,阻塞当前线程,直到dispatch_semaphore_signal(sem)调用之后

     
NSString *str = @"http://www.jianshu.com/p/6930f335adba";
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession]; dispatch_semaphore_t sem = dispatch_semaphore_create(0);
for (int i=0; i<10; i++) { NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSLog(@"%d---%d",i,i);
dispatch_semaphore_signal(sem);
}]; [task resume];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
} dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"end");
});

8.异步操作两组数据时, 执行完第一组之后, 才能执行第二组

  • 这里使用dispatch_barrier_async栅栏方法即可实现

     
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
NSLog(@"第一次任务的主线程为: %@", [NSThread currentThread]);
}); dispatch_async(queue, ^{
NSLog(@"第二次任务的主线程为: %@", [NSThread currentThread]);
}); dispatch_barrier_async(queue, ^{
NSLog(@"第一次任务, 第二次任务执行完毕, 继续执行");
}); dispatch_async(queue, ^{
NSLog(@"第三次任务的主线程为: %@", [NSThread currentThread]);
}); dispatch_async(queue, ^{
NSLog(@"第四次任务的主线程为: %@", [NSThread currentThread]);
});

9.多线程中的死锁?

死锁是由于多个线程(进程)在执行过程中,因为争夺资源而造成的互相等待现象,你可以理解为卡主了。产生死锁的必要条件有四个:

  • 互斥条件 : 指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

  • 请求和保持条件 : 指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

  • 不可剥夺条件 : 指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

  • 环路等待条件 : 指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

    最常见的就是 同步函数 + 主队列 的组合,本质是队列阻塞。

     
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
}); NSLog(@"1");
// 什么也不会打印,直接报错

10.GCD执行原理?

  • GCD有一个底层线程池,这个池中存放的是一个个的线程。之所以称为“池”,很容易理解出这个“池”中的线程是可以重用的,当一段时间后这个线程没有被调用胡话,这个线程就会被销毁。注意:开多少条线程是由底层线程池决定的(线程建议控制再3~5条),池是系统自动来维护,不需要我们程序员来维护(看到这句话是不是很开心?) 而我们程序员需要关心的是什么呢?我们只关心的是向队列中添加任务,队列调度即可。

  • 如果队列中存放的是同步任务,则任务出队后,底层线程池中会提供一条线程供这个任务执行,任务执行完毕后这条线程再回到线程池。这样队列中的任务反复调度,因为是同步的,所以当我们用currentThread打印的时候,就是同一条线程。

  • 如果队列中存放的是异步的任务,(注意异步可以开线程),当任务出队后,底层线程池会提供一个线程供任务执行,因为是异步执行,队列中的任务不需等待当前任务执行完毕就可以调度下一个任务,这时底层线程池中会再次提供一个线程供第二个任务执行,执行完毕后再回到底层线程池中。

  • 这样就对线程完成一个复用,而不需要每一个任务执行都开启新的线程,也就从而节约的系统的开销,提高了效率。在iOS7.0的时候,使用GCD系统通常只能开5~8条线程,iOS8.0以后,系统可以开启很多条线程,但是实在开发应用中,建议开启线程条数:3~5条最为合理。

其他面试题篇章:

大厂常问iOS面试题--多线程篇的更多相关文章

  1. 大厂常问iOS面试题--性能优化篇

    1.造成tableView卡顿的原因有哪些? 1.最常用的就是cell的重用, 注册重用标识符 如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell 如果有很多数据的时候 ...

  2. 2020年,大厂常问iOS面试题汇总!

    Runloop & KVO runloop app如何接收到触摸事件的 为什么只有主线程的runloop是开启的 为什么只在主线程刷新UI PerformSelector和runloop的关系 ...

  3. (转)大厂常问到的14个Java面试题

    1. synchronized和reentrantlock异同 相同点 都实现了多线程同步和内存可见性语义 都是可重入锁 不同点 实现机制不同 synchronized通过java对象头锁标记和Mon ...

  4. 点击每个li输出里面的内容(前端很常问的面试题之一)

    点击每个li输出里面的内容(前端很常问的面试题之一) 前端 面试 JavaScript <!DOCTYPE html> <html lang="en"> & ...

  5. [ Java面试题 ]多线程篇

    1.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成一 ...

  6. iOS进阶面试题----多线程

    1 多线程是什么 多线程是个复杂的概念,按字面意思是同步完成多 项任务,提高了资源的使用效率,从硬件.操作系统.应用软件不同的角度去看,多线程被赋予不同的内涵,对于硬件,现在市面上多数的CPU都是多核 ...

  7. 金九银十跳槽高峰,面试必备之 Redis + MongoDB 常问80道面试题

    前言 有着“金九银十”之称的招聘旺季已经开启,跳槽高峰期也如约而至. 本文为主要是 Redis + MongoDB 知识点的攻略,希望能帮助到大家. 内容较多,大家准备好耐心和瓜子矿泉水. Redis ...

  8. iOS开发多线程篇—多线程简单介绍

    iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...

  9. iOS开发多线程篇—线程安全

    iOS开发多线程篇—线程安全 一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...

随机推荐

  1. Java基础知识系列——日期

    日期类型也是在编程中经常用到的一种数据类型. Java中的日期类型为Date. 另外需要记住三个类: java.text.SimpleDateFormat; java.util.Calendar; j ...

  2. 【代码笔记】iOS-看图听故事

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> #import <AVFoundation/AVFo ...

  3. SQL注入常用语句

    整形参数判断     1.直接加'  2.and 1=1  3. and 1=2     如果1.3运行异常 2正常就存在注入 字符型判断     1.直接加'  2.and '1'='1'  3. ...

  4. PHPCMS如何实现后台访问限制?

    修改phpcms 后台管理路径,可以有效的防止因为程序漏洞,或者是服务器安全问题所带来的 phpcms系统管理权限被黑客获取 文件路径:/caches/config/system.php 修改:'ad ...

  5. [转帖]自动调整TextView字体大小以适应文字长度

    package com.test.android.textview; import android.content.Context; import android.graphics.Paint; im ...

  6. SendMessage发送自定义消息及消息响应

    控件向父窗体发送自定义消息,父窗体定义处理此消息的函数   效果描述: 指定哪个类添加自定义消息:(当然这个类必须是CmdTarget的子类,不然不能处理消息) 添加消息 实现消息函数:(wParam ...

  7. 走进windows编程的世界-----windows进程

    Windows进程  1 Windows进程    进程是一个容器,包括了一个应用程序实例的各种资源.Windows多任务的操作系统,因此能够同一时候运行多个进程.      2 Windows进程的 ...

  8. mysql 和php 保留2位小数

    一般交易中保留的数字的小数位数为2位(即最小单位为 1分钱[0.01元]) 数据库设计中预金钱有关或要求精准度要高的用 decimal(n,m) 表示,n表示保留的数字长度,保留的小数位数,如deci ...

  9. [emacs] org-mode的一些小技巧

    Table of Contents 1 快速输入 #+BEGIN_SRC … #+END_SRC 2 代码按语法高亮 3 导出成HTML时的一些问题和技巧 3.1 生成目录表 3.2 为每个分节的标题 ...

  10. Java高级面试题及答案

    List和Set比较,各自的子类比较 对比一:Arraylist与LinkedList的比较 1.ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高 ...