首先了解一些基本概念:git
临界区:指的是一块对公共资源进行访问的代码,并不是一种机制或是算法。github
自旋锁:是用于多线程同步的一种锁,线程反复检查锁变量是否可用。因为线程在这一过程当中保持执行,所以是一种忙等待。一旦获取了自旋锁,线程会一直保持该锁,直至显式释放自旋锁。 自旋锁避免了进程上下文的调度开销,所以对于线程只会阻塞很短期的场合是有效的。算法
互斥锁(Mutex):是一种用于多线程编程中,防止两条线程同时对同一公共资源(好比全局变量)进行读写的机制。该目的经过将代码切片成一个一个的临界区而达成。编程
读写锁:是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁) 用于解决多线程对公共资源读写问题。读操做可并发重入,写操做是互斥的。 读写锁一般用互斥锁、条件变量、信号量实现。安全
信号量(semaphore):是一种更高级的同步机制,互斥锁能够说是semaphore在仅取值0/1时的特例。信号量能够有更多的取值空间,用来实现更加复杂的同步,而不仅仅是线程间互斥。bash
条件锁:就是条件变量,当进程的某些资源要求不知足时就进入休眠,也就是锁住了。当资源被分配到了,条件锁打开,进程继续运行。多线程
死锁:指两个或两个以上的进程在执行过程当中,因为竞争资源或者因为彼此通讯而形成的一种阻塞的现象,若无外力做用,它们都将没法推动下去,这些永远在互相等待的进程称为死锁进程。并发
轮询(Polling):一种CPU决策如何提供周边设备服务的方式,又称“程控输出入”。轮询法的概念是,由CPU定时发出询问,依序询问每个周边设备是否须要其服务,有即给予服务,服务结束后再问下一个周边,接着不断周而复始。app
锁的类型:异步
互斥锁
自旋锁
读写锁
递归锁
NSRecursiveLock
pthread_mutex(recursive)(见上)
条件锁
信号量
//10000000
OSSpinLock: 112.38 ms
dispatch_semaphore: 160.37 ms
os_unfair_lock: 208.87 ms
pthread_mutex: 302.07 ms
NSCondition: 320.11 ms
NSLock: 331.80 ms
pthread_rwlock: 360.81 ms
pthread_mutex(recursive): 512.17 ms
NSRecursiveLock: 667.55 ms
NSConditionLock: 999.91 ms
@synchronized: 1654.92 ms
//1000
OSSpinLock: 0.02 ms
dispatch_semaphore: 0.03 ms
os_unfair_lock: 0.04 ms
pthread_mutex: 0.06 ms
NSLock: 0.06 ms
pthread_rwlock: 0.07 ms
NSCondition: 0.07 ms
pthread_mutex(recursive): 0.09 ms
NSRecursiveLock: 0.12 ms
NSConditionLock: 0.18 ms
@synchronized: 0.33 ms
复制代码
atomic使用的是自旋锁,主要用于赋值操做等轻量操做(散列表,引用计数,弱引用指针赋值),而互斥锁通常都是锁线程,好比单例。
首先了解一些基本概念:
因此:
在非主线程中更新UI就会有多个线程同时操做一个控件的可能,形成最后更新的结果不符合预期
多线程自己就是为了并发处理以达到高效的目的,可是刷新UI使用并发会形成安全问题,要解决上面的安全问题,那就须要给控件加锁,可是加锁必然会形成额外的开销,同时开新的线程自己就有必定的开销,因此不如直接在主线程中执行更新操做。
@interface CustomDictionary ()
//多线程须要访问的数据量
@property (nonatomic, strong) NSMutableDictionary *dataDic;
@end
//模拟场景,容许多个线程同时访问字典,可是只有一个线程能够写字典
@implementation CustomDictionary {
//定义一个并发队列
dispatch_queue_t _concurrent_queue;
}
- (instancetype)init {
if (self = [super init]) {
_concurrent_queue = dispatch_queue_create("com.mf.read_write_queue", DISPATCH_QUEUE_CONCURRENT);
_dataDic = @{}.mutableCopy;
}
return self;
}
// 读取数据,并发操做
- (id)objectForKey:(NSString *)key {
__block id obj;
//同步读取数据
dispatch_sync(_concurrent_queue, ^{
obj = [self.dataDic objectForKey:key];
});
return obj;
}
// 写入数据,异步栅栏
- (void)setObject:(id)obj forKey:(NSString *)key {
//异步栅栏调用设置数据
dispatch_barrier_async(_concurrent_queue, ^{
[self.dataDic setObject:obj forKey:key];
});
}
@end
复制代码
dispatch_queue_t queue = dispatch_queue_create("com.mf.barrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
});
dispatch_barrier_async(queue, ^{
NSLog(@"等待任务1,2上面执行完毕");
});
dispatch_async(queue, ^{
NSLog(@"3");
});
dispatch_async(queue, ^{
NSLog(@"4");
});
复制代码
// 全局变量group
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 进入组(进入组和离开组必须成对出现, 不然会形成死锁)
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"1");
//离开组
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"2");
dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^{ // 监听组里全部线程完成的状况
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任务1,2已完成");
});
});
复制代码
//建立队列
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
//建立操做
NSBlockOperation *operation1=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第1次操做,线程:%@",[NSThread currentThread]);
}];
NSBlockOperation *operation2=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第2次操做,线程:%@",[NSThread currentThread]);
}];
NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第3次操做,线程:%@",[NSThread currentThread]);
}];
//添加依赖
[operation1 addDependency:operation2];
[operation2 addDependency:operation3];
//将操做添加到队列中去
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
复制代码
/* 好比说咱们须要请求三张元素图,拼合成一张海报。咱们须要先对元素图进行请求然后才能合成海报,这就造成了依赖关系。咱们经过semaphore限制资源数为3,供请求元素图使用,待请求完成后,释放信号量,便能走到合成的耗时操做。 */
//建立信号量,参数:信号量的初值,若是小于0则会返回NULL
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
//元素图1
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//等待下降信号量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"请求第1张元素图");
sleep(1);
NSLog(@"第1张元素图Get");
//提升信号量
dispatch_semaphore_signal(semaphore);
});
//元素图2
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"请求第2张元素图");
sleep(1);
NSLog(@"第2张元素图Get");
dispatch_semaphore_signal(semaphore);
});
//元素图3
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"请求第3张元素图");
sleep(1);
NSLog(@"第3张元素图Get");
dispatch_semaphore_signal(semaphore);
});
//合成海报
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"合成海报");
sleep(1);
NSLog(@"海报Get");
dispatch_semaphore_signal(semaphore);
});
复制代码
注意:
正常的使用顺序是先下降而后再提升,这两个函数一般成对使用。
邮箱: adrenine@163.com
邮箱: holaux@gmail.com
邮箱: ledahapple@icloud.com