Objective-C中锁的几种实现方式

2019-04-25  本文已影响0人  跃文

锁的意义就是为了防止在多线程(多任务)的情况下对共享资源(临界资源)的脏读或者脏写。也可以理解为:用于执行多线程操作时强行限制资源访问的同步机制,即并发控制中保证互斥的要求,可以理解成它用于排除并发的一种策略。

分类方式 分类
按锁的粒度划分 表级锁、行级锁、页级锁
按锁的级别划分 共享锁、排他锁
按加锁方式划分 自动锁、显示锁
按锁的使用方式划分 乐观锁、悲观锁
按操作划分 DML锁、DDL锁
等等。。 等等。。
方式1 使用NSLock类
- (void)lockDemo1 {
    NSLock *myLock = [[NSLock alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [myLock lock];
        NSLog(@"执行锁1");
        sleep(5);
        [myLock unlock];
        if ([myLock tryLock]) {
            NSLog(@"可以获得锁1");
        }else {
            NSLog(@"不可以获得锁1");
        }
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        if ([myLock tryLock]) {
            NSLog(@"---可以获得锁2");
        }else {
            NSLog(@"----不可以获得所2");
        }
        [myLock lock];
        NSLog(@"执行锁2");
        [myLock unlock];
    });
}
方式2 使用@synchorize
- (void)lockDemo2 {
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       @synchronized (self) {
           NSLog(@"执行锁1");
           sleep(5);
       }
   });
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       sleep(1);
       @synchronized (self) {
           NSLog(@"执行锁2");
       }
   });
}
方式3 使用gcd
- (void)lockDemo3 {
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"执行锁1");
        sleep(5);
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"执行锁2");
        dispatch_semaphore_signal(semaphore);
    });
}
方式4 使用phtread
- (void)lockDemo4 {

    __block pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);

    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        pthread_mutex_lock(&mutex);
        NSLog(@"执行锁1");
        sleep(5);
        pthread_mutex_unlock(&mutex);
    });

    //线程2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        pthread_mutex_lock(&mutex);
        NSLog(@"执行锁2");
        pthread_mutex_unlock(&mutex);
    });
}
方式5 OSSpinLock
- (void)lockDemo4 {

    OSSpinLock spinlock = OS_SPINLOCK_INIT;

    //线程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        OSSpinLockLock(&spinlock);
        NSLog(@"执行锁1");
        sleep(5);
        OSSpinLockUnlock(&spinlock);
    });

    //线程2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        OSSpinLockLock(&spinlock);
        NSLog(@"执行锁2");
        OSSpinLockUnlock(&spinlock);
    });
}
同样加锁解锁次数耗时结果比较:

OSSpinlock < pthread_mutex < NSLock+IMP < NSLock < @synchronized

  • 1、@synchronized
    内部会创建一个异常捕获的handler和其他内部使用的锁。由于内部会添加异常处理,所以耗时。
  • 2、NSLock 和 NSLock+IMP
    两个时间非常接近。他们是 pthread mutexes 封装的,但是创建对象的时候需要额外的开销。
  • 3、pthread_mutex
    底层的API,性能比较高,处理能力不错。
  • 4、gcd
    系统封装的C代码效果比pthread好。
  • 5、OSSpinLock
    自旋锁不进入内核,仅仅是重新加载。如果自旋锁占用的时间是极少的(通常是纳秒级别的)性能还是比较高的,减少了系统的直接调用和上下文的切换。(因为优先级倒置问题已经弃用,此类已经被os_unfair_lock所替)

耗时结果如下: synthorize > NSLock > pthread > gcd > os_unfair_lock >OSSPinLock

上一篇 下一篇

猜你喜欢

热点阅读