5. 锁

作者: 算命的李老师 | 来源:发表于2020-09-25 17:45 被阅读0次
==1.@synchronize==
  • 用于单例创建,使多线程下保证唯一对象
  • 代码块可用于数组中唯一线程读写
==2.atomic==
  • 是对象的属性关键字,负责对象的原子性操作,不负责对象的使用
  • atomic 系统会在生成的setter/getter方法里添加锁,但是这个锁仅仅是保证了setter/getter存取的安全,并不能保证数据结果正确
  • A、B、C等多个线程都要操作同一个对象setter,D线程要getter这个对象的值,那么每个线程都成保证各自数据的完整性,但是D线程最后get到的值并不能确定。
==3.OSSpinlock==
自旋锁

循环等待访问,不释放当前资源,类似while(1),负责轻量级的+1,-1,如在引用计数的+1,-1操作

==4.NSRecursiveLock==
递归锁

为了解决NSLock在已加锁的情况下重复加锁,调用NSRecursiveLock的lock方法,可以使加锁之后仍然获取到锁,并且加锁。加锁解锁成对出现。解决多线程下递归方法的加锁。

==4.NSLock==

线程锁,为了解决线程同步问题

==5.dispatch_semaphore_t==

信号量,实现对线程同步,资源共享访问的信号量级锁

1.GCD信号量简介
//和GCD的group等用法一致,这个函数是创建一个dispatch_s`emaphore_类型的信号量
//并且创建的时候需要指定信号量的大小。
dispatch_semaphore_create(long value); // 创建信号量

//发送信号量。该函数会对信号量的值进行加1操作。
dispatch_semaphore_signal(dispatch_semaphore_t deem); // 发送信号量

//等待信号量。如果信号量值为0,那么该函数就会一直等待,也就是不返回(相当于阻塞当前线程)
//直到该函数等待的信号量的值大于等于1,该函数会对信号量的值进行减1操作,然后返回。
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); // 等待信号量
2.用信号量机制使异步线程完成同步操作

两个任务虽然是异步的,但仍需要同步执行

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    dispatch_group_t grp = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_group_async(grp, queue, ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        NSLog(@"task1 begin : %@",[NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"task1 finish : %@",[NSThread currentThread]);
            dispatch_semaphore_signal(sema);
        });
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        //先等待task1内的信号量 直到 task1 finish
    });
    dispatch_group_async(grp, queue, ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        NSLog(@"task2 begin : %@",[NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"task2 finish : %@",[NSThread currentThread]);
            dispatch_semaphore_signal(sema);
        });
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    });
    dispatch_group_notify(grp, dispatch_get_main_queue(), ^{
        NSLog(@"refresh UI");
    });
}
3 阻塞请求线程
dispatch_async(queue, 0), ^{
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    [网络请求:^{
        //请求回调
        dispatch_semaphore_signal(sema);  
    }];
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
});
//多个请求顺序执行
==6.dispatch_barrier_async和dispatch_barrier_sync==

栅栏方法,用GCD方式实现多读单写

dispatch_barrier_sync

需要等待栅栏执行完才会执行栅栏后面的任务

dispatch_barrier_async

无需等待栅栏执行完,会继续往下走(保留在队列里)

 dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        //会等待内部执行完才往下走
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });
    dispatch_barrier_sync(queue, ^{
        //会等待内部执行完才往下走
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });

线程安全的数组

  • 对元素的获取增加dispatch_sync
- (id)objectAtIndex:(NSUInteger)index {
   __block id item = nil;
   dispatch_sync(self.readWriteQuene, ^{
       if (index <= self.array.count - 1) {
           item = [self.array objectAtIndex:index];
       }
   });
   return item;
}
- (nullable id)getFirstObject {
   __block id item = nil;
   dispatch_sync(self.readWriteQuene, ^{
       if (self.array.count > 0) {
           item = [self.array objectAtIndex:0];
       }
   });
   return item;
}
- (nullable id)getLastObject {
   __block id item = nil;
   dispatch_sync(self.readWriteQuene, ^{
       NSUInteger size = self.array.count;
       if (size > 0) {
           item = self.array[size - 1];
       }
   });
   return item;
}
  • 对数组操作增加栅栏方法
//synchronized 效率最低
- (void)addObject:(id)anObject {
   dispatch_barrier_async(self.readWriteQuene, ^{
       [self.array addObject:anObject];
   });
}

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index {
   dispatch_barrier_async(self.readWriteQuene, ^{
       [self.array insertObject:anObject atIndex:index];
   });
}
//还有很多操作数组的方法如removeLastObject

相关文章

  • 5. 锁

    ==1.@synchronize== 用于单例创建,使多线程下保证唯一对象 代码块可用于数组中唯一线程读写 ==2...

  • 15.mysql锁问题(2)-InnoDB

    5. InnoDB 行锁 5.1 行锁介绍 行锁特点 :偏向InnoDB 存储引擎,开销大,加锁慢;会出现死锁;锁...

  • 2020-07-24

    锁 OSSpinLock 自旋锁 实现机制:忙等 操作重点:原子操作1.自旋锁2.互斥锁3.读写锁4.信号量5.条...

  • MySQL面试题 | 附答案解析(十)

    接上篇:锁 5. MySQL中InnoDB引擎的行锁是怎么实现的? 答:InnoDB是基于索引来完成行锁 例: s...

  • 浅析mysql的锁

    目录:1.锁的定义与分类(表、行、页)2.锁相关的语句(查看锁)3.mysql事务4.乐观锁和悲观锁5.数据库死锁...

  • 后端工程师技术要点

    基础: 1. 分布式锁 2. AOP 实现缓存 3. HSF 4. 动态代理 5. 多线程 6. 乐观锁悲观锁 7...

  • 5. Java中的锁

    Lock接口 需要显式的获取和释放锁,支持非阻塞的获取锁,支持中断的获取锁,支持超时获取锁; Synchronze...

  • 5. Java中的锁

    本文将介绍Java并发包中与锁相关的API和组件, 以及这些API和组件的使用方式和实现细节 1. Lock接口 ...

  • 5. Mysql技术内幕-锁

    锁 什么是锁 锁是数据库系统区别于文件系统的关键特性,用于管理对共享资源的并发访问,比如记录和操作缓冲池LRU列表...

  • 创建型模式 --- 单例

    1.懒汉式,线程不安全 2.懒汉式,线程安全 3.饿汉式,线程安全 4.枚举,线程安全 5.双检锁/双重校验锁

网友评论

      本文标题:5. 锁

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