Skip to content

Latest commit

 

History

History
221 lines (179 loc) · 8.79 KB

多线程面试题.md

File metadata and controls

221 lines (179 loc) · 8.79 KB

什么是进程?什么是线程?

点击查看我的回答 进程是系统的最小单元,一个程序在系统中拥有一个进程。系统由多个进程组成,一个进程拥有独立的内存区域。一个进程可以拥有多个线程,但是一定存在一个主线程。线程之间公用内存区域。主线程最大拥有1M的内存空间,子线程最大拥有512K的内存空间。

什么是多线程?

点击查看回答 因为CPU一次只能执行一个任务,但是CPU的处理速度十分的快。迅速的切换处理任务,就造成了并发执行的假象。这样的处理任务就叫做多线程。 多线程是从硬件或者软件实现多个线程并发执行的技术。

多线程的优缺点

查看回答 优点是可以充分的利用多核的特性充分的利用资源,可以节省等待任务完成的时间。缺点是新增加一个子线程就要开辟512K的内存空间,造成内存暴涨。CPU的调用任务增多,造成运行温度升高,如果创建的子线程过多,可能造成程序卡死。多线程因为是资源共享,如果加锁不当则直接导致崩溃,加锁会影响程序的运行性能。

线程创建实际的开销在内存方面是有多大?

查看答案 创建一个线程需要消耗90毫秒在栈创建512K的内存空间,占据1K的内核空间。

多线程在开发中的使用场景?

查看答案
  • 网络请求

  • 图片下载

  • 文件处理

  • 数据存储

  • 其他异步执行的任务

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

查看答案 iOS中实现多线程主要有四种方式
  • pthread

这个是基于C的线程管理,跨平台,使用复杂,程序员管理,iOS开发中也不会去使用。

  • NSThread

这个是基于面向对象操作线程的,使用起来简单。局限性较强,不能设置依赖,当线程开始时候也不能取消线程。线程程序员自己管理,线程之间无法通信。

  • GCD

基于C语言封装的线程管理,程序自己管理。基于闭包,使用简单。GCD分为异步执行和同步执行,一个线程分串行和并发两种。GCD常用dispatch_one用于一次执行代码创建单利,dispatch_apply可以异步执行循环,提高执行效率。dispatch_group可以同时异步一组任务等待完成。dispatch_barrier_async通过设置阻断可以让一些线程先执行,一些线程后执行。dispatch_semaphore可以进行数据加锁操作,也可以等待线程处理。dispatch_after可以做延时操作,dispatch_time可以做定时器。

  • NSOperation

是基于GCD的封装,面向对象。没有GCD使用方便简单,但是可以添加线程依赖,并且支持线程取消,程序自己管理线程。对于创建的NSOperation添加到NSOperationQueue可以自动异步执行。没有添加直接执行start方法的会在当前线程执行任务。我们通常通过NSOperation的两个子类进行创建,也可以自己创建NSOperation子类自定义来使用。

线程之间如何通信?

查看答案
  • performSelector:onThread:withObject:waitUntilDone:方法

  • NSMachPort

多线程的底层实现?

查看答案 底层是基于Mach线程实现的

谈谈多线程安全问题的几种解决方案?

查看答案 我们通畅在开发中可以通过下面的集中方案解决线程安全,最简单是使用atomic保证属性访问的线程安全,但是对于可变的数组和字典来说不是线程安全的。还可以通过NSLock进行加锁,可以通过dispatch_semaphore信号量保持线程同步,还可以用@synchronized保障self线程安全。还可以使用POSIX互斥锁来解决线程安全,不太常用。

使用atomic一定是线程安全的吗?

查看答案 如果是基本变量类型是线程安全的,atomic线程安全核心是在属性的set和get方法内部自动加锁。但是只是保证了属性的赋值和获取加锁。但是比如针对于可变的数组和字典,对于数组和字典变更内容没有没有加锁的,所以atomic不是绝对线程安全的。

如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

查看答案 这个我们知道多线程实现方案有四种,pthread难用还不如NSTheard明显不行。NSTheard只针对单个线程使用,功能少,线程通信都没。NSOperation这个特点就是依赖和取消线程,明显也不能解决。剩下就只能用GCD来解决了,通过对于GCD的了解,我们可以用dispatch_group和信号量来做。
  • 利用dispatch_group
  dispatch_group_t group = dispatch_group_create();
  dispatch_queue_t queue = dispatch_queue_create("dispatch_group", DISPATCH_QUEUE_CONCURRENT);
  dispatch_group_async(group, queue, ^{
      NSLog(@"下载图片1");
  });
  dispatch_group_async(group, queue, ^{
      NSLog(@"下载图片2");
  });
  dispatch_group_async(group, queue, ^{
      NSLog(@"下载图片3");
  });
  dispatch_group_async(group, queue, ^{
      NSLog(@"下载图片4");
  });
  dispatch_group_notify(group, queue, ^{
      NSLog(@"合成图片完成");
  });
  • dispatch_barrier_async阻断
  dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
  dispatch_async(queue, ^{
      NSLog(@"下载图片1");
  });
  dispatch_async(queue, ^{
      NSLog(@"下载图片2");
  });
  dispatch_async(queue, ^{
      NSLog(@"下载图片3");
  });
  dispatch_async(queue, ^{
      NSLog(@"下载图片4");
  });
  dispatch_barrier_async(queue, ^{
      NSLog(@"合成图片");
  });
  • dispatch_semaphore信号量
  dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
  dispatch_semaphore_t semaphore = dispatch_semaphore_create(4);
  dispatch_async(queue, ^{
      NSLog(@"下载图片1");
      dispatch_semaphore_signal(semaphore);
  });
  dispatch_async(queue, ^{
      NSLog(@"下载图片2");
      dispatch_semaphore_signal(semaphore);
  });
  dispatch_async(queue, ^{
      NSLog(@"下载图片3");
      dispatch_semaphore_signal(semaphore);
  });
  dispatch_async(queue, ^{
      NSLog(@"下载图片4");
      dispatch_semaphore_signal(semaphore);
  });
  dispatch_async(queue, ^{
      for (NSUInteger i = 0; i < 4; i ++) {
          dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
      }
      NSLog(@"合成图片");
  });
  • NSOperation
      NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"operation1");
  }];
  NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"operation2");
  }];
  NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"operation3");
  }];
  NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"operation4");
  }];
  NSBlockOperation *operation5 = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"operation5");
  }];
  [operation5 addDependency:operation1];
  [operation5 addDependency:operation2];
  [operation5 addDependency:operation3];
  [operation5 addDependency:operation4];
  [queue addOperations:@[operation1,operation2,operation3,operation4,operation5] waitUntilFinished:YES];

苹果为什么要废弃dispatch_get_current_queue

查看答案 很容易导致死锁

如果让你来实现 dispatch_once,你会怎么做?

查看答案 我们都知道dispatch_one声明一个静态变量。猜测一定是根据静态变量是否初始化来控制后面是否还执行。为了做到对于静态变量访问和修改,我们可以采用信号量等让后面执行的进行等待,之后等第一个运行完毕根据静态变量是否初始化来是否运行任务。

如何实现同步,有多少方式就说多少

查看答案
  • 使用dispatch_sync同步的执行代码

  • DISPATCH_QUEUE_SERIAL串行队列

  • dispatch_barrier阻断

  • dispatch_semaphore信号量

  • 设置线程数量为1

  • 用NSOperation设置串行依赖