互斥锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

@property(nonatomic, assign) init tickets;

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.tickets = 20;

NSThread * t1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
[t1 start];

NSThread * t2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
[t2 start];
}

- (void)saleTickets {
while(YES) {
[NSThread sleepForTimeInterval: 1.0];
// 互斥锁可以让锁内代码同一时间只被一条线程运行
@synchronized(self) {
if(self.tickets > 0) {
self.tickets--;
NSLog(@"剩下%d张票", self.tickets);
} else {
NSLog(@"卖完了");
break;
}
}
}
}

自旋锁

原子属性内部的锁

1
@property(atomic, assign) init tickets;

相同点与不同的

相同点

  • 消耗性能、效率不高
  • 能够保证线程安全

不同点

  • 自旋锁读取时不会锁
  • 线程被互斥锁锁在外面,线程会进入休眠状态,等待锁打开后被唤醒
  • 线程被自旋锁锁在外面,线程会进入死循环状态等待开锁

RunLoop

主线程默认开启RunLoop,子线程默认关闭,需要手动开启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@interface ViewController()
@property(assign, nonatomic, getter=isFinished)BOOL finished
@end

- (void)viewDidLoad {
[super viewDidLoad];

// 先执行demo
NSThread * t1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
[t1 start];

self.finished = NO;

// 然后执行otherMethod
// 如果不设置t1的RunLoop,执行完demo是不会执行otherMethod的
[self performSelector:@selector(otherMethod) onThread:t1 withObject:nil waitUntilDone:NO];
}

- (void)demo {
NSLog(@"before");
while(!self.isFinished) {
// 开启RunLoop查询当前线程有没有事件
[[NsRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
NSLog(@"after");
}

}

- (void)otherMethod {
NSLog(@"otherMethod function");
// 执行完第二个方法后设置为YES
self.finished = YES;
}

// 另一种方式 一般不用 很难停下来
[[NSRunLoop currentRunLoop] run];

RunLoopMode

  • NSDefaultRunLoop 时钟、网络事件模式,操作UI界面会停止执行,执行会非常耗时
  • NSRunLoopCommonModes 用户交互模式