浅谈Objective-C 的几种多线程加锁用法

        最近看了一些关于ios下多线程的数据加锁保护代码。初略总结了几种常用的多线程下的加锁方法。

        最常见的大概就是我们对于“加锁”最直观最了当的理解,NSLock。即用同一把锁对需要加锁保护的代码进行加解锁保护。

        创建一个操作对象类 TestLockObj 。代码如下:

//
//  TestLockObj.h
//  Robin_Test_Learn
//
//  Created by Jiabin He on 14-8-27.
//  Copyright (c) 2014年 Robin. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface TestLockObj : NSObject

//多线程下操作的两个方法 method1 ,method2
- (void) method1;
- (void) method2;

@end
       
//
//  TestLockObj.m
//  Robin_Test_Learn
//
//  Created by Jiabin He on 14-8-27.
//  Copyright (c) 2014年 Robin. All rights reserved.
//

#import "TestLockObj.h"

@implementation TestLockObj

/**
 *  跟踪查看这两个方法调用的前后顺序
 *  打印出调用方法名称  NSStringFromSelector()
 */

-(void)method1{
    NSLog(@"%@",NSStringFromSelector(_cmd));
}

-(void)method2{
    NSLog(@"%@",NSStringFromSelector(_cmd));
}

@end

NSLock 的加解锁保护执行代码如下:

    /**
     *   NSLock
     */
    
    //创建一个锁对象,后面加解锁都必须用同一把锁进行操作
    TestLockObj *testObj = [[TestLockObj alloc] init];
    NSLock *lock = [[NSLock alloc] init];
    
    //使用 dispatch_async() 函数开启一个线程1  传入dispatch_global_queue 全局队列,为并发队列
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [lock lock];
        [testObj method1];
        sleep(10);//为了达到后面的线程同步访问的效果
        [lock unlock];
    
    });
    
    //使用 dispatch_async() 函数开启一个线程2  传入dispatch_global_queue 全局队列,为并发队列
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);//这里休眠一秒,保证线程1首先被执行
        [lock lock];
        [testObj method2];
        [lock unlock];
    });
    
    [lock release];
    [testObj release];

执行结果为:

2014-10-09 15:40:40.283 Robin_Test_Learn[3311:144545] method1
2014-10-09 15:40:50.287 Robin_Test_Learn[3311:144546] method2

线程1首先被执行,执行后线程1先休眠10秒。线程2休眠1秒后也被执行,但是由于对象testObj被锁lock加锁保护,所以在线程1访问testObj期间,线程2只能阻塞,等待线程1执行访问完成后再继续执行。

   

介绍的第二种加锁方式就是使用 @synchronized()指令函数。

指令@synchronized()通过对一段代码的使用进行加锁,即这个指令可以将{ } 内的代码限制在一个线程执行。其他试图执行该段代码的线程都会被阻塞,直到加锁线程退出执行该段被保护的代码段。

指令@synchronized()需要一个参数。该参数可以使任何的Objective-C对象,包括self。这个对象就是互斥信号量。他能够让一个线程对一段代码进行保护,避免别的线程执行该段代码。

@synchronized()一般在公用变量的时候使用,如单例模式或者操作类的static变量中使用。

代码如下:

还是使用上面的操作对象类 TestLockObj

    /**
     *   @synchronized
     */
    TestLockObj *testObj = [[TestLockObj alloc] init];
    
    //使用 dispatch_async() 函数开启一个线程1  传入dispatch_global_queue 全局队列,为并发队列
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @synchronized(testObj){//testObj对象作为互斥信号量
        [testObj method1];
        sleep(10);
        }
        
    });
    
    //使用 dispatch_async() 函数开启一个线程2  传入dispatch_global_queue 全局队列,为并发队列
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @synchronized(testObj){//testObj对象作为同一个互斥信号量
            [testObj method2];
        }
        
    });

需要注意的是上面两个线程对于@synchronized()指令的参数即互斥信号量必须是一致(testObj),才能达到线程间的互斥作用,达到加锁的功能。结果和上面的NSLock加锁效果一样。


介绍的第三种加锁方式就是使用 GCD中的Serial queues(即用户队列,串行队列)

代码如下:

还是使用上面的操作对象类 TestLockObj

    /**
     *   serial_queues
     */
    TestLockObj *testObj = [[TestLockObj alloc] init];
    
    //创建serial_queues 用户队列,为串行队列
    dispatch_queue_t  myQueue = dispatch_queue_create("com.SerialQueue", Nil);
    
    //使用 dispatch_async() 函数开启一个线程1  传入serial_queues 用户队列,为串行队列
    dispatch_async(myQueue, ^{
        [testObj method1];
        sleep(10);
    
    });
    
    //使用 dispatch_async() 函数开启一个线程2  传入serial_queues 用户队列,为串行队列
    dispatch_async(myQueue, ^{
        sleep(1);
        [testObj method2];
        
    });

上面的代码中,首先创建一个serial_queues 用户队列(myQueue),该队列为串行队列。然后使用dispatch_async() 函数开启两个线程,将两个任务添加到同一个串行队列(myQueue)中。由于是串行队列,所以,添加到该队列中的任务都将按照添加的先后顺序依次执行,达到加锁的目的。

运行结果和上面两种加锁方法的一致。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值