iOS多线程中的锁
来源:互联网 发布:强制起床闹钟软件 编辑:程序博客网 时间:2024/06/15 18:51
锁的类别:互斥锁,递归锁,条件锁,自旋锁等
锁的实现方式:NSLock,NSRecursiveLock, NSConditionLock,@synchronized,GCD的信号量等
下面说一下常用的几种锁:
1.@synchronized:对象级别所,互斥锁,性能较差不推荐使用
@synchronized(这里添加一个OC对象,一般使用self) {
这里写要加锁的代码
}
@synchronized使用注意点
1.加锁的代码尽量少
2.添加的OC对象必须在多个线程中都是同一对象,下面举一个反例
- (
void
)viewDidLoad {
[
super
viewDidLoad];
//设置票的数量为5
_tickets = 5;
//线程一
NSThread
*threadOne = [[
NSThread
alloc] initWithTarget:
self
selector:
@selector
(saleTickets) object:
nil
];
threadOne.name = @
"threadOne"
;
//线程二
NSThread
*threadTwo = [[
NSThread
alloc] initWithTarget:
self
selector:
@selector
(saleTickets) object:
nil
];
//开启线程
[threadOne start];
[threadTwo start];
}
- (
void
)saleTickets
{
NSObject
*object = [[
NSObject
alloc] init];
while
(1)
{
@synchronized
(object) {
[
NSThread
sleepForTimeInterval:1];
if
(_tickets > 0)
{
_tickets--;
NSLog
(@
"剩余票数= %ld"
,_tickets);
}
else
{
NSLog
(@
"票卖完了"
);
break
;
}
}
}
}
结果卖票又出错了,出现这个原因的问题是每个线程都会创建一个object对象,锁后面加的object在不同线程中就不同了;
把@synchronized(object)改成 @synchronized(self)就能得到了正确结果
2.NSLock:互斥锁,
@interface
ViewController ()
{
NSLock
*mutexLock;
}
@property
(assign,
nonatomic
)
NSInteger
tickets;
@end
@implementation
ViewController
- (
void
)viewDidLoad {
[
super
viewDidLoad];
//创建锁
mutexLock = [[
NSLock
alloc] init];
//设置票的数量为5
_tickets = 5;
//线程一
NSThread
*threadOne = [[
NSThread
alloc] initWithTarget:
self
selector:
@selector
(saleTickets) object:
nil
];
threadOne.name = @
"threadOne"
;
//线程二
NSThread
*threadTwo = [[
NSThread
alloc] initWithTarget:
self
selector:
@selector
(saleTickets) object:
nil
];
//开启线程
[threadOne start];
[threadTwo start];
}
- (
void
)saleTickets
{
while
(1)
{
[
NSThread
sleepForTimeInterval:1];
//加锁
[mutexLock lock];
if
(_tickets > 0)
{
_tickets--;
NSLog
(@
"剩余票数= %ld"
,_tickets);
}
else
{
NSLog
(@
"票卖完了"
);
break
;
}
//解锁
[mutexLock unlock];
}
}
NSLock: 使用注意,不能多次调用 lock方法,会造成死锁
3.NSRecursiveLock:递归锁
@interface
ViewController ()
{
NSRecursiveLock
*rsLock;
}
@property
(assign,
nonatomic
)
NSInteger
tickets;
@end
@implementation
ViewController
- (
void
)viewDidLoad {
[
super
viewDidLoad];
//创建锁递归锁
rsLock = [[
NSRecursiveLock
alloc] init];
//设置票的数量为5
_tickets = 5;
//线程一
NSThread
*threadOne = [[
NSThread
alloc] initWithTarget:
self
selector:
@selector
(saleTickets) object:
nil
];
threadOne.name = @
"threadOne"
;
//线程二
NSThread
*threadTwo = [[
NSThread
alloc] initWithTarget:
self
selector:
@selector
(saleTickets) object:
nil
];
//开启线程
[threadOne start];
[threadTwo start];
}
- (
void
)saleTickets
{
while
(1)
{
[
NSThread
sleepForTimeInterval:1];
//加锁,递归锁可以多次加锁
[rsLock lock];
[rsLock lock];
if
(_tickets > 0)
{
_tickets--;
NSLog
(@
"剩余票数= %ld"
,_tickets);
}
else
{
NSLog
(@
"票卖完了"
);
break
;
}
//解锁,只有对应次数解锁,其他线程才能访问。
[rsLock unlock];
[rsLock unlock];
}
}
4.NSConditionLock:条件锁
NSConditionLock:条件锁,一个线程获得了锁,其它线程等待。
[xxxx lock]; 表示 xxx 期待获得锁,如果没有其他线程获得锁(不需要判断内部的condition) 那它能执行此行以下代码,如果已经有其他线程获得锁(可能是条件锁,或者无条件锁),则等待,直至其他线程解锁
[xxx lockWhenCondition:A条件]; 表示如果没有其他线程获得该锁,但是该锁内部的condition不等于A条件,它依然不能获得锁,仍然等待。如果内部的condition等于A条件,并且没有其他线程获得该锁,则进入代码区,同时设置它获得该锁,其他任何线程都将等待它代码的完成,直至它解锁。
[xxx unlockWithCondition:A条件]; 表示释放锁,同时把内部的condition设置为A条件
@interface
ViewController () {
NSConditionLock
*_cdtLock;
//条件锁
}
@end
@implementation
ViewController
- (
void
)viewDidLoad {
[
super
viewDidLoad];
//创建条件锁
_cdtLock = [[
NSConditionLock
alloc] init];
[
NSThread
detachNewThreadSelector:
@selector
(conditionLockAction1) toTarget:
self
withObject:
nil
];
[
NSThread
detachNewThreadSelector:
@selector
(conditionLockAction2) toTarget:
self
withObject:
nil
];
}
- (
void
)conditionLockAction1 {
//阻塞线程2s
[
NSThread
sleepForTimeInterval:2];
for
(
NSInteger
i = 0; i < 3; i++) {
//加锁
[_cdtLock lock];
NSLog
(@
"i = %li"
, i);
//释放锁,并设置condition属性的值为i
[_cdtLock unlockWithCondition:i];
}
}
- (
void
)conditionLockAction2 {
//当标识为2时同步代码段才能够执行,如果标识为其它数字则当前线程被阻塞。
[_cdtLock lockWhenCondition:2];
NSLog
(@
"thread2"
);
[_cdtLock unlock];
}
打印结果:
如果我们把代码中[_cdtLock lockWhenCondition:2]换成[_cdtLock lockWhenCondition:1]则会发现出现如下结果
和我们预想的在i = 1后面打印thread2不符合,这是因为conditionLockAction1中的代码段也需要获得锁,同时在循环执行过后把condition置成了2,那么conditionLockAction2就再也没机会加锁了,所以不打印thread2。
我们可以靠下面的代码验证
@interface
ViewController () {
NSConditionLock
*_cdtLock;
//条件锁
}
@end
@implementation
ViewController
- (
void
)viewDidLoad {
[
super
viewDidLoad];
//创建条件锁
_cdtLock = [[
NSConditionLock
alloc] init];
[
NSThread
detachNewThreadSelector:
@selector
(conditionLockAction1) toTarget:
self
withObject:
nil
];
[
NSThread
detachNewThreadSelector:
@selector
(conditionLockAction2) toTarget:
self
withObject:
nil
];
}
- (
void
)conditionLockAction1 {
//阻塞线程2s
[
NSThread
sleepForTimeInterval:2];
for
(
NSInteger
i = 0; i < 3; i++) {
//加锁
[_cdtLock lock];
NSLog
(@
"i = %li"
, i);
//释放锁,并设置condition属性的值为i
[_cdtLock unlockWithCondition:i];
//在i 为 1的时候阻塞线程1s
if
(i == 1)
{
[
NSThread
sleepForTimeInterval:1];
}
}
}
- (
void
)conditionLockAction2 {
//当标识为2时同步代码段才能够执行,如果标识为其它数字则当前线程被阻塞。
[_cdtLock lockWhenCondition:1];
NSLog
(@
"thread2"
);
[_cdtLock unlock];
}
现在的结果就和我们预期的一样了
5.NSCondition:可以理解为互斥锁和条件锁的结合
用生产者消费者中的例子可以很好的理解NSCondition
1.生产者要取得锁,然后去生产,生产后将生产的商品放入库房,如果库房满了,则wait,就释放锁,直到其它线程唤醒它去生产,如果没有满,则生产商品后调用signal,可以唤醒在此condition上等待的线程。
2.消费者要取得锁,然后去消费,如果当前没有商品,则wait,释放锁,直到有线程去唤醒它消费,如果有商品,则消费后会通知正在等待的生产者去生产商品。
生产者和消费者的关键是:当库房已满时,生产者等待,不再继续生产商品,当库房已空时,消费者等待,不再继续消费商品,走到库房有商品时,会由生产者通知消费来消费。
- (
void
)conditionTest
{
//创建数组存放商品
products = [[
NSMutableArray
alloc] init];
condition = [[
NSCondition
alloc] init];
[
NSThread
detachNewThreadSelector:
@selector
(createProducter) toTarget:
self
withObject:
nil
];
[
NSThread
detachNewThreadSelector:
@selector
(createConsumenr) toTarget:
self
withObject:
nil
];
}
- (
void
)createConsumenr
{
while
(1) {
//模拟消费商品时间,让它比生产慢一点
[
NSThread
sleepForTimeInterval:arc4random()%10 * 0.1 + 1.5];
[condition lock];
while
(products.count == 0) {
NSLog
(@
"商品为0,等待生产"
);
[condition wait];
}
[products removeLastObject];
NSLog
(@
"消费了一个商品,商品数 = %ld"
,products.count);
[condition signal];
[condition unlock];
}
}
- (
void
)createProducter
{
while
(1) {
//模拟生产商品时间
[
NSThread
sleepForTimeInterval:arc4random()%10 * 0.1 + 0.5];
[condition lock];
while
(products.count == 5)
{
NSLog
(@
"商品满了,等待消费"
);
[condition wait];
}
[products addObject:[[
NSObject
alloc] init]];
NSLog
(@
"生产了一个商品,商品数%ld"
,products.count);
[condition signal];
[condition unlock];
}
}
了解死锁
概念:死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
产生死锁的4个必要条件
- iOS多线程中的锁
- ios 开发中的多线程
- ios 开发中的多线程
- iOS中的多线程
- IOS中的多线程
- iOS 中的多线程总结
- iOS中的多线程
- IOS 中的多线程问题
- iOS开发中的多线程
- iOS中的多线程编程
- iOS中的多线程
- iOS中的多线程
- iOS中的多线程
- iOS中的GCD多线程
- iOS开发 中的 多线程
- IOS中的多线程
- iOS中的多线程使用
- 浅谈iOS中的多线程
- 英语7月份总结-就是干!
- 干货:阮一峰老师深入浅出谈http协议
- 最小割 [国家集训队2011]happiness(吴确)
- 精析背包四讲
- 小狗吃骨头(DFS+剪枝)
- iOS多线程中的锁
- CodeForces #426 div2 A The Useless Tony
- 整合在线流程图设计器及遇到的问题(三)
- CSS3布局相关样式
- CSU1562-Fun House
- git 的使用
- sql的四种联接小总
- 微信小程序周报(第九期)-极乐科技
- Codeforces 834 B The Festive Evening