参考 :
https://www.cnblogs.com/jukaiit/p/5570056.html
https://www.cnblogs.com/CoderAlex/p/5257339.html
http://www.cocoachina.com/ios/20161205/18279.html
http://www.jianshu.com/p/1e59f0970bf5
首先我们知道@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对锁对象进行修改。这个是objective-c的一个锁定令牌,防止锁对象在同一时间内被其它线程访问,起到线程的保护作用。
指令@synchronized()通过对一段代码的使用进行加锁。其他试图执行该段代码的线程都会被阻塞,直到加锁线程退出执行该段被保护的代码段
相关术语:
线程同步:多天线程在同一条线上执行(按顺序的执行任务)
互斥锁就是使用了线程同步技术
下面看互斥锁使用格式
@synchronized (锁对象) {
加锁代码
}
锁定一份代码只能用一把锁,多把锁是无效的。
优点:防止多线程操作时资源竞争导致的数据安全问题
缺点:需要消耗大量的CPU资源
互斥锁的使用前提是:多条线程使用同一份资源。
查看该段的汇编代码可知主要使用了两个函数
_objc_sync_enter
_objc_sync_exit
在Objective-C 中查看源码
int objc_sync_enter(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
SyncData* data = id2data(obj, ACQUIRE);
assert(data);
data->mutex.lock();
} else {
// @synchronized(nil) does nothing
if (DebugNilSync) {
_objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
}
objc_sync_nil();
}
return result;
}
// End synchronizing on 'obj'.
// Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
int objc_sync_exit(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
SyncData* data = id2data(obj, RELEASE);
if (!data) {
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
} else {
bool okay = data->mutex.tryUnlock();
if (!okay) {
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
}
}
} else {
// @synchronized(nil) does nothing
}
return result;
}
查看SyncData
typedef struct SyncData {
struct SyncData* nextData;
DisguisedPtr<objc_object> object;
int32_t threadCount; // number of THREADS using this block
recursive_mutex_t mutex;
} SyncData;
可见在SyncData 维护了一个递归锁,所以如下代码就不会死锁。
@synchronized (obj) {
NSLog(@"13qw");
@synchronized (obj) {
NSLog(@"2asda");
}
}
但是并不意味着synchronized不会死锁,类似下面的代码还是会导致死锁的
@synchronized (self) {
[_sharedLock lock];
NSLog(@"code in class A");
[_sharedLock unlock];
}
正确使用@synchronized还需要注意粒度控制
@synchronized (token) {
[arrA addObject:obj];
}
@synchronized (token) {
[arrB addObject:obj];
}
使用同一个token来同步arrA和arrB的访问,虽然arrA和arrB之间没有任何联系。传入self的就更不对了。
应该是不同的数据使用不同的锁,尽量将粒度控制在最细的程度。上述代码应该是:
@synchronized (tokenA) {
[arrA addObject:obj];
}
@synchronized (tokenB) {
[arrB addObject:obj];
}
@synchronized(nil)不起任何作用,所以传参时还是需要做好判断
注意内部的函数调用
@synchronized (tokenA) {
[arrA addObject:obj];
[self doSomething:arrA];
}