synchronized
synchronized是对p_thread_mutex的封装,也能对线程进行加锁,从而实现线程同步。
看代码:
[[[NSThread alloc] initWithTarget:self selector:@selector(thread1) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(thread2) object:nil] start];
- (void)thread1{
@synchronized (self) {
NSLog(@"%s", __func__);
}
}
- (void)thread2{
@synchronized (self) {
NSLog(@"%s", __func__);
}
}
最后能保证thread1方法在thread2方法之前执行。一个对象对应一把锁。synchronized使用起来相对方便,但由于它封装的较多,所以性能并不是很好。
为什么要获取某个对象?
传入nil不起作用。
传入的object的内存地址作为key,通过hash map对应的一个系统维护的递归锁。
传入self容易导致死锁。
//class A
@synchronized (self) {
[_sharedLock lock];
NSLog(@"code in class A");
[_sharedLock unlock];
}
//class B
[_sharedLock lock];
@synchronized (objectA) {
NSLog(@"code in class B");
}
[_sharedLock unlock];
如上面代码所示,self被用作key生成同一把锁,两个公共锁交替使用容易出现死锁,正确的做法是传入一个类内部维护的NSObject对象,而且这个对象是外部不可见的。(引用自该篇文章:https://www.jianshu.com/p/2dc347464188)
dispatch_semaphore_t
dispatch_semaphore_t也能实现线程同步。
看代码:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.semaphore = dispatch_semaphore_create(1);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (NSInteger i = 0; i < 10; i ++) {
dispatch_async(queue, ^{
[self test];
});
}
}
- (void)test{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"begin。。。");
sleep(3);
NSLog(@"test:%@", [NSThread currentThread]);
dispatch_semaphore_signal(self.semaphore);
}
在创建semaphore的时候,初始参数为1就能保证线程的同步。其中的参数是指线程最大并发数。那么我们也就可以利用GCD中的semaphore设置线程的最大并发数了。
这里还有semaphore异步变同步的用法
iOS开发中GCD的一些用法