seo网站关键词优化多少钱,如何自己制作图片,精细化学品网站建设,公司网站域名做邮箱文章目录 前言1. 你理解的多线程优点缺点 2. atomic 和 nonatomic 的区别及其作用3. GCD的队列类型 - 三种队列类型4. GCD的死锁问题线程死锁的四个必要条件 5. 多线程之间的区别和联系6. 进程和线程#xff1f;进程间的通信方式线程间的通信方式 6. iOS的线程安全手段如何保证… 文章目录 前言1. 你理解的多线程优点缺点 2. atomic 和 nonatomic 的区别及其作用3. GCD的队列类型 - 三种队列类型4. GCD的死锁问题线程死锁的四个必要条件 5. 多线程之间的区别和联系6. 进程和线程进程间的通信方式线程间的通信方式 6. iOS的线程安全手段如何保证 前言
iOS 锁和多线程的总结
1. 你理解的多线程
多线程是同时执行多个线程子任务的能力用于提高程序性能和响应性。它允许在一个程序中并发地处理多个任务。
并发在一个时间段多个线程同时进行计算机通过切换不同的线程实现多线程任务。
优点
大大提高了程序的运行速度。使用线程可以把占据时间较长的任务放到后面去处理从而提升用户的体验。
缺点
如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。更多的线程需要更多的内存空间。
2. atomic 和 nonatomic 的区别及其作用
atomic原子操作加锁保证setter和getter存取方法的线程安全仅仅对setter和getter方法加锁。因为线程加锁别的线程访问当前属性的时候会先执行完属性当前的操作。
对同一对象的set和get的操作是顺序执行的。速度不快因为要保证操作整体完成。线程安全需要消耗大量系统资源为属性加锁。使用atomic并不能保证绝对的线程安全因为atomic仅仅是对系统生成的的setter和getter方法加锁 对于绝对保证线程安全的操作需要使用更高级的方式处理NSSpinLock, syncronized 锁保证线程安全。
nanatomic非原子操作不加锁线程执行快但是多个线程访问同一个属性可能产生crash。
不是默认的速度更快如果有两个线程访问同一个属性可能造成crash。非线程安全
atomic与nonatom的主要区别就是系统自动生成的getter/setter方法不一样
atomic系统自动生成的getter/setter方法会进行加锁操作。nonatomic系统自动生成的getter/setter方法不会进行加锁操作。
⚠️atomic修饰的属性,系统生成的 getter/setter 会保证 get、set 操作的完整性不受其他线程影响。比如线程 A 的 getter 方法运行到一半线程 B 调用了 setter那么线程 A 的 getter 还是能得到一个完好无损的对象。
3. GCD的队列类型 - 三种队列类型
The main queue主线程串行队列与主线程功能相同提交到main queue的任务会在主线程中执行。
dispatch_get_main_queue() 来获取Global queue全局并发队列) 全局并发队列由整个进程共享有 高 中默认是中 低和后台四个优先级别。
dispatch_get_global_queue() 可以设置优先级Custom queue(自定义队列) 可以串行,也可以并发。
dispatch_queue_create()4. GCD的死锁问题
线程死锁的四个必要条件
互斥 一个资源每次都只能被一个进程占用。占有且等待一个进程本身占有资源一种或多种同时还有资源未得到满足正在等待其他进程释放该资源。不可抢占别人已经占有了某项资源你不能因为自己需要资源而去抢占其他资源。循环等待 存在一个进程链使得每个进程都占有下一个进程所需要的至少一种资源。
概念所谓死锁通常是两个线程A和B都卡住了A在等BB在等A互相等待到值死锁。
.主线程串行队列同步执行任务,在主线程运行时,会产生死锁
NSLog(1); // 任务1
dispatch_sync(dispatch_get_main_queue(), ^{NSLog(2); // 任务2
});
NSLog(3); // 任务3分析
dispatch_sync表示是一个同步线程dispatch_get_main_queue表示运行在主线程中的主队列任务2是同步线程的任务。任务3需要等待任务2结束之后再执行.
为什么造成死锁
首先执行任务1这是肯定没问题的只是接下来程序遇到了同步线程那么它会进入等待等待任务2执行完然后执行任务3。但这是主队列是一个特殊的串行队列,有任务来当然会将任务加到队尾然后遵循FIFO原则执行任务。那么现在任务2就会被加到最后任务3排在了任务2前面 任务3要等任务2执行完才能执行任务2又排在任务3后面意味着任务2要在任务3执行完才能执行所以他们进入了互相等待的局面。【既然这样那干脆就卡在这里吧】这就是死锁。 同步异步互相嵌套
// 同步 异步 互相嵌套产生死锁
- (void)sync_async {dispatch_queue_t queue dispatch_queue_create(com.demo.serialQueue, DISPATCH_QUEUE_SERIAL);NSLog(1); // 任务1dispatch_async(queue, ^{NSLog(2); // 任务2dispatch_sync(queue, ^{NSLog(3); // 任务3});NSLog(4); // 任务4});NSLog(5); // 任务5
}分析首先通过自定义队列创建了dispatch_queue_create函数创建了一个DISPATCH_QUEUE_SERIAL的串行队列。
执行任务1.遇到异步线程将【任务2、同步线程、任务4】加入串行队列中。因为是异步线程所以在主线程中的任务5不必等待异步线程中的所有任务完成因为任务5不必等待所以2和5的输出顺序不能确定任务2执行完以后遇到同步线程这时将任务3加入串行队列又因为任务4比任务3早加入串行队列所以任务3要等待任务4完成以后才能执行。但是任务3所在的同步线程会阻塞所以任务4必须等任务3执行完以后再执行。这就又陷入了无限的等待中造成死锁。 主线程无限循环
- (void)async_loop {dispatch_async(dispatch_get_global_queue(0, 0), ^{NSLog(1); // 任务1dispatch_sync(dispatch_get_main_queue(), ^{NSLog(2); // 任务2});NSLog(3); // 任务3});NSLog(4); // 任务4while (1) {}NSLog(5); // 任务5// a打印 4 1 / 1 4 顺序不定
}打印结果 4 1 / 1 4 顺序不定
分析
先来看看都有哪些任务加入了Main Queue【异步线程、任务4、死循环、任务5】。在加入到Global Queue异步线程中的任务有【任务1、同步线程、任务3】。第一个就是异步线程任务4不用等待所以结果任务1和任务4顺序不一定。任务4完成后程序进入死循环Main Queue阻塞。但是加入到Global Queue的异步线程不受影响继续执行任务1后面的同步线程。同步线程中将任务2加入到了主线程并且任务3等待任务2完成以后才能执行。这时的主线程已经被死循环阻塞了。所以任务2无法执行当然任务3也无法执行在死循环后的任务5也不会执行。
最终只能得到1和4顺序不定的结果。
5. 多线程之间的区别和联系 GCD和NSOperation
GCD的执行效率更高执行的是由Block构成的任务是一个轻量级的数据结构写起来更加方便GCD只支持FIFO队列NSOperationQueue可以通过设置最大并发数、设置优先级、添加依赖关系来调整执行顺序NSOperation可以跨越队列设置依赖关系GCD仅仅能通过栅栏等方法才能控制执行顺序NSOperation更加面向对象支持KVO也可以通过继承等关系添加子类。所以如果我们需要考虑异步操作之间的顺序行、依赖关系比如多线程并发下载等等就使用NSOperation
GCD 与 NSThread 的区别
NSThread 通过 selector 指定要执行的方法代码分散, 依靠的是NSObject的分类实现的线程之间的通讯如果要开线程必须创建多个线程对象。经常只用的是[NSTread current] 查看当前的线程。NSThread是一个控制线程执行的对象它不如NSOperation抽象通过它我们可以方便的得到一个线程并控制它。但NSThread的线程之间的并发控制是需要我们自己来控制的可以通过NSCondition实现。GCD 通过 block 指定要执行的代码代码集中, 所有的代码写在一起的让代码更加简单易于阅读和维护,不需要管理线程的创建/销毁/复用的过程程序员不用关心线程的生命周期
6. 进程和线程
参考进程和线程的概念、区别及进程线程间通信 1. 基本概念
进程是对运行时程序的封装是系统进行资源调度和分配的基本单位实现了操作系统的并发。线程是进程的子任务是CPU调度和分配的基本单位用于保障程序执行的实时性实现进程内部的并发。线程是操作系统可以识别的最小执行和调度单位。每个线程都肚子占用一个虚拟处理器等每个线程完成不同的任务但是共享同一地址空间也就是同样的动态内存映射文件目标代码等等打开的文件队列和其他内核资源。
2. 区别
一个线程只能属于一个进程而一个进程可以有多个线程但至少有一个线程。线程依赖于进程而存在。进程是资源分配的最小单位线程是CPU调度的最小单位进程在执行过程中拥有独立的内存单元而多个线程共享进程的内存。资源分配给进程同一进程的所有线程共享该进程的所有资源。同一进程中的多个线程共享代码段代码和常量数据段全局变量和静态变量扩展段堆存储。但是每个线程拥有自己的栈段栈段又叫运行时段用来存放所有局部变量和临时变量。进程间不会相互影响 线程一个线程挂掉将导致整个进程挂掉线程之间的通信更加方便同一个进程下线程共享全局变量静态变量等数据。
3. 通信方式
进程间的通信方式
进程间通信主要包括管道、系统IPC包括消息队列、信号量、信号、共享内存等、以及套接字socket。信号量semaphore与已经介绍过的 IPC 结构不同它是一个计数器可以用来控制多个进程对共享资源的访问。信号量用于实现进程间的互斥与同步而不是用于存储进程间通信数据。
线程间的通信方式
临界区通过多线程的串行化来访问公共资源或一段代码速度快适合控制数据访问互斥量Synchronized/Lock采用互斥对象机制只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个所以可以保证公共资源不会被多个线程同时访问信号量Semphare为控制具有有限数量的用户资源而设计的它允许多个线程在同一时刻去访问同一个资源但一般需要限制同一时刻访问此资源的最大线程数目。事件(信号)Wait/Notify通过通知操作的方式来保持多线程同步还可以方便的实现多线程优先级的比较操作进程间通信的方式
6. iOS的线程安全手段如何保证
参考iOS中有哪些技术可以保证线程安全 问1块资源可能会被多个线程共享也就是多个线程可能会访问同一块资源比如多个线程访问同一个对象、同一个变量、同一个文件。当多个线程访问同一块资源时很容易引发数据错乱和数据安全问题。此时我们需要用线程锁来解决。
线程数据安全的方法
natomic原子操作使用atomic多线程原子性控制atomic的原理给setter加上锁getter不会加锁。使用GCD实现atomic操作给某字段的setter方法和getter方法加上同步队列
- (void)setCount:(NSInteger)newcount
{dispatch_sync(_synQueue, ^{count newcount;});
}
- (NSInteger)count
{__block NSInteger localCount;dispatch_sync(_synQueue, ^{localCount count;});return localCount;
}互斥锁能够有效的防止因多线程抢夺资源造成的数据安全问题但是需要消耗大量的CPU资源。
互斥锁 使用互斥锁可以确保同一时间只有一个线程访问共享资源。例如synchronized创建互斥锁
synchronized (self) {// 访问共享资源的代码
}
自旋锁自旋锁Spin Lock自旋锁一种忙等待的锁它会不断地尝试获取锁直到成功为止。在Objective-C中可以使用os_unfair_lock来创建自旋锁。信号量Semaphore信量是一种数器用于控制同时访问某个资源的线程数量。
dispatch_semaphore_t semaphore dispatch_semaphore_create(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 访问共享资源的代码
dispatch_semaphore_signal(semaphore);
串行队列串行队列Serial Queue使用串行队列可以确保任务按顺序执行从而避多个线程同时访问共享资源。可以使用GCD(Grand Central Dispatch来创建串行队列。
dispatch_queue_t serialQueue dispatch_queue_create(com.example.serialQueue DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{// 访问共享资源的代码
});