线程锁

(atomic是只对set加锁,对get不加锁,所以在获取的时候会有误差)

·@synchronized

synchronized的使用形式是

@synchronized (object) {
    //需要保护的代码块
}

设计的一个类

@interface SynchronizObj : NSObject

- (void)synchronizMethod;
- (void)normalMethod;

@end

@implementation SynchronizObj

- (void)synchronizMethod
{
    @synchronized (self) {
        
        NSLog(@"synchronizMethod");
        sleep(5);
        
    }
}

- (void)testLock
{
    static NSObject *lock = nil;
    
    if (!lock) {
        lock = [[NSString alloc] init];
    }
        
    @synchronized(lock){
        NSLog(@"开始枷锁");
        sleep(5);
    }
}

- (void)normalMethod
{
    NSLog(@"normalMethod");
}

@end

(1)直接调用这个类

SynchronizObj *obj = [[SynchronizObj alloc] init];
    
[obj synchronizMethod];
[obj normalMethod];

得到的结果是

19:31:09.855 LockDemo[1120:135454] synchronizMethod
19:31:14.857 LockDemo[1120:135454] normalMethod

相差了5秒执行.

(2)我们把这个放到异步执行里面看一下如何

dispatch_async(dispatch_get_main_queue(), ^{
    [obj testLock];
});

dispatch_async(dispatch_get_main_queue(), ^{
    sleep(1);//让synchronizMethod先执行
    [obj testLock];
});

结果
22:12:21.745 LockDemo[1144:141456] 开始枷锁
22:12:27.889 LockDemo[1144:141446] 开始枷锁

放到异步里,只相差6秒执行,可以看到,testLock中@synchronized保护的代码块,在未返回的情况下,其他线程是无法访问。

(3)@synchronized需要一个参数,如果传递的是不同的参数呢?我们把测试的类的代码修改一下

- (void)synchronizMethod:(id)obj;
- (void)normalMethod:(id)obj;

- (void)synchronizMethod:(id)obj
{
    @synchronized (self) {
        
        NSLog(@"synchronizMethod:%@", obj);
        sleep(5);
        
    }
}

- (void)normalMethod:(id)obj
{
    @synchronized (self) {
        NSLog(@"normalMethod");
    }
}

调用代码和结果

SynchronizObj *obj = [[SynchronizObj alloc] init];
SynchronizObj *obj1 = [[SynchronizObj alloc] init];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [obj synchronizMethod:obj];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);//让obj synchronizMethod先执行
    [obj normalMethod:obj];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);//让obj synchronizMethod先执行
    [obj1 synchronizMethod:obj];
});

结果

20:05:46.491 LockDemo[1199:156733] synchronizMethod:<SynchronizObj: 0x7fd632f0b000>
20:05:47.492 LockDemo[1199:156740] synchronizMethod:<SynchronizObj: 0x7fd632f0b000>
20:05:51.497 LockDemo[1199:156744] normalMethod

可以看到,多线程中,@synchronized获取的是不同的参数,是不会阻塞的,但如果是同一个参数,则只有一个会获得锁,直到锁保护的内容执行完毕。

·NSLock

NSLock等是实现了NSLocking协议,所以具备了lock和unlock这一对上锁解锁的方法,这一对方法需要在同一线程中,否则会导致报错(先调用了unlock,没有或者后调用了lock)或者无法持有锁(上一个lock未调用unlock)。

一般是这样调用

NSLock* lock = [[NSLock alloc] init];
    
dispatch_async(dispatch_get_main_queue(), ^{
    [lock lock];
    NSLog(@"任务1");
    sleep(1);
    [lock unlock];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);// 让任务1先执行
    [lock lock];
    NSLog(@"任务2");
    [lock unlock];
});

结果
20:23:43.869 LockDemo[1263:169163] 任务1
20:23:44.870 LockDemo[1263:169200] 任务2

·NSConditionLock

NSConditionLock顾名思义,叫做条件锁,根据某种条件进行上锁解锁,但这个条件,必须是个NSInteger变量。

NSConditionLock有这么几个特别的地方:

- (instancetype)initWithCondition:(NSInteger)condition;
@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;

NSConditionLock有个condition属性,只读的,使用上面两个方法进行上锁和解锁的时候,lockWhenCondition时,会将参数condition和自身的condition属性进行比较,如果相同,才能进行上锁操作,否则会处于等待;unlockWithCondition时,会将参数condition自动赋值给自身的condition属性,用于之后的对比。同样,调用initWithCondition初始化,也会将condition赋值。

文档中用生产和消费举例,下面是我的测试代码和结果

NSConditionLock* lock = [[NSConditionLock alloc] init];
NSMutableArray* products = [NSMutableArray array];

#define hasData YES
#define noData NO

dispatch_async(dispatch_get_main_queue(), ^{
    
    for (int i = 0; i < 3; i ++) {
        
        [lock lockWhenCondition:noData];
        
        [products addObject:@"product"];
        NSLog(@"生产产品%d condition:%ld", i, lock.condition);
        
        [lock unlockWithCondition:hasData];
        
    }
    
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);// 让任务1先执行
    
    for (int i = 0; i < 3; i ++) {
        
        [lock lockWhenCondition:hasData];
        
        [products removeAllObjects];
        NSLog(@"消费产品%d condition:%ld", i, lock.condition);
        
        [lock unlockWithCondition:noData];
        
    }
    
});


结果
20:45:59.579 LockDemo[1297:184273] 生产产品0 condition:0
20:46:00.580 LockDemo[1297:184322] 消费产品0 condition:1
20:46:00.580 LockDemo[1297:184273] 生产产品1 condition:0
20:46:00.581 LockDemo[1297:184322] 消费产品1 condition:1
20:46:00.581 LockDemo[1297:184273] 生产产品2 condition:0
20:46:00.581 LockDemo[1297:184322] 消费产品2 condition:1

·NSRecursiveLock

NSRecursiveLock,递归锁,允许在同一线程中多次持有锁,但每次持有必须配对解锁。

@property (nonatomic, strong) NSRecursiveLock* lock;

- (void)testMethod {
    
    _lock = [[NSRecursiveLock alloc] init];
    [self testRecursiveLock:5];
    
}

- (void)testRecursiveLock:(NSInteger)value
{
    
    [_lock lock];
    
    if (value > 0) {
        
        NSLog(@"第%ld次持有锁", 6 - value);
        
        -- value;
        [self testRecursiveLock:value];
        
    }
    
    [_lock unlock];
    
}

结果
21:06:27.322 LockDemo[1327:190602] 第1次持有锁
21:06:27.323 LockDemo[1327:190602] 第2次持有锁
21:06:27.323 LockDemo[1327:190602] 第3次持有锁
21:06:27.323 LockDemo[1327:190602] 第4次持有锁
21:06:27.323 LockDemo[1327:190602] 第5次持有锁

不同线程持有锁,按照基本情况,即先持有锁的线程先执行,直到最终释放锁。比如对上面的代码做修改,在递归期间,有另一线程请求锁

- (void)testMethod {
    
    _lock = [[NSRecursiveLock alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        sleep(1);// 让递归程序先执行
        [_lock lock];
        NSLog(@"异步加锁");
        sleep(5);
        NSLog(@"异步解锁");
        [_lock unlock];
        
    });
    
    [self testRecursiveLock:5];
    
}

- (void)testRecursiveLock:(NSInteger)value
{
    
    [_lock lock];
    
    if (value > 0) {
        
        NSLog(@"第%ld次持有锁", 6 - value);
        
        sleep(1);
        -- value;
        [self testRecursiveLock:value];
        
    }
    
    [_lock unlock];
    
}

结果
21:12:03.876 LockDemo[1357:194699] 第1次持有锁
21:12:04.877 LockDemo[1357:194699] 第2次持有锁
21:12:05.878 LockDemo[1357:194699] 第3次持有锁
21:12:06.879 LockDemo[1357:194699] 第4次持有锁
21:12:07.879 LockDemo[1357:194699] 第5次持有锁
21:12:08.881 LockDemo[1357:194735] 异步加锁
21:12:13.884 LockDemo[1357:194735] 异步解锁

上面的测试代码,先在主线程持有递归锁,其他线程之后请求锁的时候,需要等待主线程的递归锁把锁保护内容执行完毕,即递归调用完成,而不是在某一次的unlock后就获得锁资源。

·NSCondition

NSCondition看起来和NSConditionLock很像,但其实差别还是挺大的。

文档中推荐NSCondition的使用步骤是

  • lock the condition
  • while (!(boolean_predicate)) {
  •     wait on condition
  • }
  • do protected work
  • (optionally, signal or broadcast the condition again or change a predicate value)
  • unlock the condition

 NSCondition的使用和POSIX很类似,都需要加(推荐加)boolean_predicate来确保这个过程。因为操作系统的设计,允许NSCondition返回一个虚假的成功信号,在没有触发你的代码情况下,唤醒NSCondition锁住的线程。

测试代码如下

@property (atomic, assign) BOOL ready_to_go;


NSCondition* condition = [[NSCondition alloc] init];

_ready_to_go = NO;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
    [condition lock];
    
    if (_ready_to_go == NO) {
        
        NSLog(@"等待1");
        
        [condition wait];
        
    }
    
    NSLog(@"执行1");
    
    [condition unlock];
    
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
    sleep(3);
    [condition lock];
    
    _ready_to_go = YES;
    
    NSLog(@"执行2");
    
    [condition broadcast];//触发所有等待condition的线程
    // 也可以使用这个[condition signal];
    
    [condition unlock];
    
});

结果
21:48:04.434 LockDemo[1392:217171] 等待1
21:48:07.435 LockDemo[1392:217182] 执行2
21:48:07.435 LockDemo[1392:217171] 执行1

虽然任务1先执行,但由于标识不符合,所以进入等待,任务2执行后,更新标识,才触发到任务1的执行。

转载于:https://my.oschina.net/u/574245/blog/726158

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django是一个基于Python的开源Web应用框架,它提供了一套完整的工具和库,用于帮助开发人员快速构建高效、安全和可扩展的Web应用程序。 在Django中,线程锁是一种用于控制并发访问的机制,它可以确保在多个线程同时访问共享资源时的数据一致性和正确性。线程锁可以防止多个线程同时修改同一个资源,从而避免数据竞争和不一致的结果。 Django提供了多种线程锁的实现方式,其中最常用的是使用Python标准库中的`threading`模块提供的锁机制。通过使用`threading.Lock()`创建一个锁对象,并使用`acquire()`方法获取锁,在操作共享资源之前调用`acquire()`方法可以确保只有一个线程可以访问资源。在操作完成后,使用`release()`方法释放锁,以便其他线程可以获取锁并进行操作。 以下是一个简单的示例代码,演示了如何在Django中使用线程锁: ```python import threading # 创建一个全局锁对象 lock = threading.Lock() def my_view(request): # 获取锁 lock.acquire() try: # 执行需要保护的操作 # ... finally: # 释放锁 lock.release() ``` 在上述示例中,`my_view`是一个Django视图函数,通过获取锁对象并在需要保护的操作前后调用`acquire()`和`release()`方法,确保了在同一时间只有一个线程可以执行需要保护的操作。 需要注意的是,线程锁只能在同一个进程内的多个线程之间起作用,如果是多个进程之间的并发访问,需要使用进程锁或其他机制来实现并发控制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值