上篇多线程(二)我们看了多线程的死锁和队列组的使用,下面我们再来看看多线程的安全隐患
代码详见 gitHub_Demo
多线程的安全隐患
存钱/取钱
卖票
代码演示
#import "ViewController_6.h"
@interface ViewController_6 ()
@property (assign, nonatomic) int ticketsCount;
@property (assign, nonatomic) int money;
@end
@implementation ViewController_6
- (void)viewDidLoad {
[super viewDidLoad];
[self moneyTest];
[self ticketTest];
}
/**
存钱、取钱演示
*/
- (void)moneyTest{
self.money = 100;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self saveMoney];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self drawMoney];
}
});
}
/**
存钱
*/
- (void)saveMoney{
int oldMoney = self.money;
sleep(.2);
oldMoney += 50;
self.money = oldMoney;
NSLog(@"存50,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
}
/**
取钱
*/
- (void)drawMoney{
int oldMoney = self.money;
sleep(.2);
oldMoney -= 20;
self.money = oldMoney;
NSLog(@"取20,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
}
/**
卖1张票
*/
- (void)saleTicket{
int oldTicketsCount = self.ticketsCount;
sleep(.2);
oldTicketsCount--;
self.ticketsCount = oldTicketsCount;
NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);
}
/**
卖票演示
*/
- (void)ticketTest{
self.ticketsCount = 15;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self saleTicket];
}
});
}
@end
多线程安全隐患分析
多线程安全隐患的解决方案
iOS中的线程同步方案
OSSpinLock 不再安全的 OSSpinLock
#import "ViewController_7.h"
#import
@interface ViewController_7 ()
@property (assign, nonatomic) int money;
@property (assign, nonatomic) int ticketsCount;
@property (assign, nonatomic) OSSpinLock lock;
@property (assign, nonatomic) OSSpinLock lock1;
@end
@implementation ViewController_7
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化锁
self.lock = OS_SPINLOCK_INIT;
self.lock1 = OS_SPINLOCK_INIT;
[self ticketTest];
[self moneyTest];
}
/**
存钱、取钱演示
*/
- (void)moneyTest{
self.money = 100;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self saveMoney];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self drawMoney];
}
});
}
/**
存钱
*/
- (void)saveMoney{
// 加锁
OSSpinLockLock(&_lock1);
int oldMoney = self.money;
sleep(.2);
oldMoney += 50;
self.money = oldMoney;
NSLog(@"存50,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
// 解锁
OSSpinLockUnlock(&_lock1);
}
/**
取钱
*/
- (void)drawMoney{
// 加锁
OSSpinLockLock(&_lock1);
int oldMoney = self.money;
sleep(.2);
oldMoney -= 20;
self.money = oldMoney;
NSLog(@"取20,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
// 解锁
OSSpinLockUnlock(&_lock1);
}
/**
卖1张票
*/
- (void)saleTicket{
// 加锁
OSSpinLockLock(&_lock);
int oldTicketsCount = self.ticketsCount;
sleep(.2);
oldTicketsCount--;
self.ticketsCount = oldTicketsCount;
NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);
// 解锁
OSSpinLockUnlock(&_lock);
}
/**
卖票演示
*/
- (void)ticketTest{
self.ticketsCount = 15;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self saleTicket];
}
});
}
@end
弊端:会出现优先级反转(感兴趣的自己可以细入研究)
补充:
只【当前文件】可以访问(static),全局变量初始化最好放在initialize里面(用到的时候在初始化),如:
static OSSpinLock moneyLock_; //下划线在后面(全局变量)
+ (void)initialize{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
moneyLock_ = 0;
});
}
static NSString *A = @"1111"; //可以
static NSString *A = test(); //不可以 (函数调用了,函数是在运行的时候执行的)(static是在编译的时候)
解决:
static NSString *str = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
str = test();
});
os_unfair_lock
YDBaseDemo.h
#import
@interface YDBaseDemo : NSObject
- (void)moneyTest;
- (void)ticketTest;
#pragma mark - 暴露给子类去使用
- (void)__saveMoney;
- (void)__drawMoney;
- (void)__saleTicket;
@end
YDBaseDemo.m
#import "YDBaseDemo.h"
@interface YDBaseDemo()
@property (assign, nonatomic) int money;
@property (assign, nonatomic) int ticketsCount;
@end
@implementation YDBaseDemo
/**
存钱、取钱演示
*/
- (void)moneyTest{
self.money = 100;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self __saveMoney];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self __drawMoney];
}
});
}
/**
存钱
*/
- (void)__saveMoney{
int oldMoney = self.money;
sleep(.2);
oldMoney += 50;
self.money = oldMoney;
NSLog(@"存50,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
}
/**
取钱
*/
- (void)__drawMoney{
int oldMoney = self.money;
sleep(.2);
oldMoney -= 20;
self.money = oldMoney;
NSLog(@"取20,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
}
/**
卖1张票
*/
- (void)__saleTicket{
int oldTicketsCount = self.ticketsCount;
sleep(.2);
oldTicketsCount--;
self.ticketsCount = oldTicketsCount;
NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);
}
/**
卖票演示
*/
- (void)ticketTest{
self.ticketsCount = 15;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self __saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self __saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self __saleTicket];
}
});
}
@end
OSUnfairLockDemo.h
#import "YDBaseDemo.h"
@interface OSUnfairLockDemo : YDBaseDemo
@end
OSUnfairLockDemo.m
#import "OSUnfairLockDemo.h"
#import
@interface OSUnfairLockDemo()
// Low-level lock的特点等不到锁就休眠
@property (assign, nonatomic) os_unfair_lock moneyLock;
@property (assign, nonatomic) os_unfair_lock ticketLock;
@end
@implementation OSUnfairLockDemo
- (instancetype)init{
if (self = [super init]) {
self.moneyLock = OS_UNFAIR_LOCK_INIT;
self.ticketLock = OS_UNFAIR_LOCK_INIT;
}
return self;
}
- (void)__saleTicket{
os_unfair_lock_lock(&_ticketLock);
[super __saleTicket];
os_unfair_lock_unlock(&_ticketLock);
}
- (void)__saveMoney{
os_unfair_lock_lock(&_moneyLock);
[super __saveMoney];
os_unfair_lock_unlock(&_moneyLock);
}
- (void)__drawMoney{
os_unfair_lock_lock(&_moneyLock);
[super __drawMoney];
os_unfair_lock_unlock(&_moneyLock);
}
@end
调用:
OSUnfairLockDemo *demo = [[OSUnfairLockDemo alloc]init];
[demo ticketTest];
[demo moneyTest];
pthread_mutex
MutexDemo.h
#import "YDBaseDemo.h"
@interface MutexDemo : YDBaseDemo
@end
MutexDemo.m
#import "MutexDemo.h"
#import
@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t ticketMutex;
@property (assign, nonatomic) pthread_mutex_t moneyMutex;
@end
@implementation MutexDemo
- (void)__initMutex:(pthread_mutex_t *)mutex{
// 初始化锁
pthread_mutex_init(mutex, NULL); //传入空就是Default
}
- (instancetype)init{
if (self = [super init]) {
[self __initMutex:&_ticketMutex];
[self __initMutex:&_moneyMutex];
}
return self;
}
- (void)__saleTicket{
pthread_mutex_lock(&_ticketMutex);
[super __saleTicket];
pthread_mutex_unlock(&_ticketMutex);
}
- (void)__saveMoney{
pthread_mutex_lock(&_moneyMutex);
[super __saveMoney];
pthread_mutex_unlock(&_moneyMutex);
}
- (void)__drawMoney{
pthread_mutex_lock(&_moneyMutex);
[super __drawMoney];
pthread_mutex_unlock(&_moneyMutex);
}
- (void)dealloc{
pthread_mutex_destroy(&_moneyMutex);
pthread_mutex_destroy(&_ticketMutex);
}
@end
调用:
MutexDemo *demo = [[MutexDemo alloc]init];
[demo ticketTest];
[demo moneyTest];
pthread_mutex – 递归锁
#import "MutexDemo2.h"
#import
@interface MutexDemo2()
@property (assign, nonatomic) pthread_mutex_t mutex;
@end
@implementation MutexDemo2
- (void)__initMutex:(pthread_mutex_t *)mutex{
// 递归锁:允许同一个线程对一把锁进行重复加锁
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
// 初始化锁
pthread_mutex_init(mutex, &attr);
// 销毁属性
pthread_mutexattr_destroy(&attr);
}
- (instancetype)init{
if (self = [super init]) {
[self __initMutex:&_mutex];
}
return self;
}
/**
线程1:otherTest(+-)
otherTest(+-)
otherTest(+-)
线程2:otherTest(等待)
*/
- (void)otherTest{
pthread_mutex_lock(&_mutex);
NSLog(@"%s", __func__);
static int count = 0;
NSLog(@"%d",count);
if (count < 10) {
count++;
[self otherTest];
}
pthread_mutex_unlock(&_mutex);
}
- (void)dealloc{
NSLog(@"%s", __func__);
pthread_mutex_destroy(&_mutex);
}
@end
pthread_mutex – 条件
#import "MutexDemo3.h"
#import
@interface MutexDemo3()
@property (assign, nonatomic) pthread_mutex_t mutex;
@property (assign, nonatomic) pthread_cond_t cond;
@property (strong, nonatomic) NSMutableArray *data;
@end
@implementation MutexDemo3
- (instancetype)init{
if (self = [super init]) {
// 初始化属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
// 初始化锁
pthread_mutex_init(&_mutex, &attr);
// 销毁属性
pthread_mutexattr_destroy(&attr);
// 初始化条件
pthread_cond_init(&_cond, NULL);
self.data = [NSMutableArray array];
}
return self;
}
- (void)otherTest{
[[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}
// 生产者-消费者模式
// 线程1
// 删除数组中的元素
- (void)__remove{
pthread_mutex_lock(&_mutex);
NSLog(@"__remove - begin");
if (self.data.count == 0) {
// 等待
pthread_cond_wait(&_cond, &_mutex); //等待的时候,会放开此时的锁
}
[self.data removeLastObject];
NSLog(@"删除了元素");
pthread_mutex_unlock(&_mutex);
}
// 线程2
// 往数组中添加元素
- (void)__add{
pthread_mutex_lock(&_mutex);
sleep(1);
[self.data addObject:@"Test"];
NSLog(@"添加了元素");
// 信号
pthread_cond_signal(&_cond);//唤醒线程
// 广播
//pthread_cond_broadcast(&_cond); //一次性唤醒多个线程
pthread_mutex_unlock(&_mutex);
NSLog(@"--");
}
- (void)dealloc{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond);
}
@end
NSLock、NSRecursiveLock
NSLockDemo.h
#import "YDBaseDemo.h"
@interface NSLockDemo : YDBaseDemo
@end
NSLockDemo.m
#import "NSLockDemo.h"
@interface NSLockDemo()
@property (strong, nonatomic) NSLock *ticketLock;
@property (strong, nonatomic) NSLock *moneyLock;
@end
@implementation NSLockDemo
- (instancetype)init{
if (self = [super init]) {
self.ticketLock = [[NSLock alloc] init];
self.moneyLock = [[NSLock alloc] init];
}
return self;
}
- (void)__saleTicket{
[self.ticketLock lock];
[super __saleTicket];
[self.ticketLock unlock];
}
- (void)__saveMoney{
[self.moneyLock lock];
[super __saveMoney];
[self.moneyLock unlock];
}
- (void)__drawMoney{
[self.moneyLock lock];
[super __drawMoney];
[self.moneyLock unlock];
}
@end
调用:
NSLockDemo *demo = [[NSLockDemo alloc]init];
[demo ticketTest];
[demo moneyTest];
NSCondition
#import "NSConditionDemo.h"
@interface NSConditionDemo()
@property (strong, nonatomic) NSCondition *condition;
@property (strong, nonatomic) NSMutableArray *data;
@end
@implementation NSConditionDemo
- (instancetype)init{
if (self = [super init]) {
self.condition = [[NSCondition alloc] init];
self.data = [NSMutableArray array];
}
return self;
}
- (void)otherTest{
[[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}
// 生产者-消费者模式
// 线程1
// 删除数组中的元素
- (void)__remove{
[self.condition lock];
NSLog(@"__remove - begin");
if (self.data.count == 0) {
// 等待
[self.condition wait];
}
[self.data removeLastObject];
NSLog(@"删除了元素");
[self.condition unlock];
}
// 线程2
// 往数组中添加元素
- (void)__add{
[self.condition lock];
sleep(1);
[self.data addObject:@"Test"];
NSLog(@"添加了元素");
// 信号
[self.condition signal];
// 广播
// [self.condition broadcast];
[self.condition unlock];
// <==>(这样就无需等待解锁了)
// [self.condition unlock];
// [self.condition signal];
}
@end
NSConditionLock
#import "NSConditionLockDemo.h"
@interface NSConditionLockDemo()
@property (strong, nonatomic) NSConditionLock *conditionLock;
@end
@implementation NSConditionLockDemo
- (instancetype)init{
if (self = [super init]) {
self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
}
return self;
}
- (void)otherTest{
[[[NSThread alloc] initWithTarget:self selector:@selector(__one) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__two) object:nil] start];
[[[NSThread alloc] initWithTarget:self selector:@selector(__three) object:nil] start];
}
- (void)__one{
[self.conditionLock lock];
NSLog(@"__one");
sleep(1);
[self.conditionLock unlockWithCondition:2];
}
- (void)__two{
[self.conditionLock lockWhenCondition:2];
NSLog(@"__two");
sleep(1);
[self.conditionLock unlockWithCondition:3];
}
- (void)__three{
[self.conditionLock lockWhenCondition:3];
NSLog(@"__three");
[self.conditionLock unlock];
}
@end
SerialQueue
YDBaseDemo.h
#import
@interface YDBaseDemo : NSObject
- (void)moneyTest;
- (void)ticketTest;
#pragma mark - 暴露给子类去使用
- (void)__saveMoney;
- (void)__drawMoney;
- (void)__saleTicket;
@end
YDBaseDemo.m
#import "YDBaseDemo.h"
@interface YDBaseDemo()
@property (assign, nonatomic) int money;
@property (assign, nonatomic) int ticketsCount;
@end
@implementation YDBaseDemo
/**
存钱、取钱演示
*/
- (void)moneyTest{
self.money = 100;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self __saveMoney];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 10; i++) {
[self __drawMoney];
}
});
}
/**
存钱
*/
- (void)__saveMoney{
int oldMoney = self.money;
sleep(.2);
oldMoney += 50;
self.money = oldMoney;
NSLog(@"存50,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
}
/**
取钱
*/
- (void)__drawMoney{
int oldMoney = self.money;
sleep(.2);
oldMoney -= 20;
self.money = oldMoney;
NSLog(@"取20,还剩%d元 - %@", oldMoney, [NSThread currentThread]);
}
/**
卖1张票
*/
- (void)__saleTicket{
int oldTicketsCount = self.ticketsCount;
sleep(.2);
oldTicketsCount--;
self.ticketsCount = oldTicketsCount;
NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);
}
/**
卖票演示
*/
- (void)ticketTest{
self.ticketsCount = 15;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self __saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self __saleTicket];
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
[self __saleTicket];
}
});
}
@end
SerialQueueDemo.h
#import "YDBaseDemo.h"
@interface SerialQueueDemo : YDBaseDemo
@end
SerialQueueDemo.m
#import"SerialQueueDemo.h"
@interface SerialQueueDemo()
@property (strong, nonatomic) dispatch_queue_t ticketQueue;
@property (strong, nonatomic) dispatch_queue_t moneyQueue;
@end
@implementation SerialQueueDemo
- (instancetype)init{
if (self = [super init]) {
self.ticketQueue = dispatch_queue_create("ticketQueue", DISPATCH_QUEUE_SERIAL);
self.moneyQueue = dispatch_queue_create("moneyQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)__drawMoney{
dispatch_sync(self.moneyQueue, ^{
[super __drawMoney];
});
}
- (void)__saveMoney{
dispatch_sync(self.moneyQueue, ^{
[super __saveMoney];
});
}
- (void)__saleTicket{
dispatch_sync(self.ticketQueue, ^{
[super __saleTicket];
});
}
@end
dispatch_semaphore
SemaphoreDemo.h
#import "YDBaseDemo.h"
@interface SemaphoreDemo : YDBaseDemo
- (void)otherTest;
@end
SemaphoreDemo.m
#import "SemaphoreDemo.h"
@interface SemaphoreDemo()
@property (strong, nonatomic) dispatch_semaphore_t semaphore;
@property (strong, nonatomic) dispatch_semaphore_t ticketSemaphore;
@property (strong, nonatomic) dispatch_semaphore_t moneySemaphore;
@end
@implementation SemaphoreDemo
- (instancetype)init{
if (self = [super init]) {
self.semaphore = dispatch_semaphore_create(5);
self.ticketSemaphore = dispatch_semaphore_create(1);
self.moneySemaphore = dispatch_semaphore_create(1);
}
return self;
}
- (void)__drawMoney{
dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
[super __drawMoney];
dispatch_semaphore_signal(self.moneySemaphore);
}
- (void)__saveMoney{
// sleep(1);
dispatch_semaphore_wait(self.moneySemaphore, DISPATCH_TIME_FOREVER);
[super __saveMoney];
dispatch_semaphore_signal(self.moneySemaphore);
}
- (void)__saleTicket{
dispatch_semaphore_wait(self.ticketSemaphore, DISPATCH_TIME_FOREVER);
[super __saleTicket];
dispatch_semaphore_signal(self.ticketSemaphore);
}
- (void)otherTest{
for (int i = 0; i < 20; i++) {
[[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
}
}
// 线程10、7、6、9、8
- (void)test{
// 如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码
// 如果信号量的值 <= 0,就会休眠等待,直到信号量的值变成>0,就让信号量的值减1,然后继续往下执行代码
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
sleep(2);
NSLog(@"test - %@", [NSThread currentThread]);
// 让信号量的值+1
dispatch_semaphore_signal(self.semaphore);
}
@end
调用:
SemaphoreDemo *demo = [[SemaphoreDemo alloc]init];
[demo moneyTest];
[demo ticketTest];
[demo otherTest];
@synchronized
下载runtime源码【objc4-750】 在objc-sync.mm文件里面发现
// Begin synchronizing on 'obj'.
// Allocates recursive mutex associated with 'obj' if needed.
// Returns OBJC_SYNC_SUCCESS once lock is acquired.
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;
}
SynchronizedDemo.h
#import "YDBaseDemo.h"
@interface SynchronizedDemo : YDBaseDemo
- (void)otherTest;
@end
SynchronizedDemo.m
#import "SynchronizedDemo.h"
@implementation SynchronizedDemo
- (void)__drawMoney{
@synchronized([self class]) {
[super __drawMoney];
}
}
- (void)__saveMoney{
@synchronized([self class]) { // objc_sync_enter
[super __saveMoney];
} // objc_sync_exit
}
- (void)__saleTicket{
static NSObject *lock;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
lock = [[NSObject alloc] init];
});
@synchronized(lock) {
[super __saleTicket];
}
}
- (void)otherTest{
static int i = 0;
@synchronized([self class]) {
I++;
NSLog(@"i=%d",i);
if(i==10){
NSLog(@"over");
}else{
[self otherTest];
}
}
}
@end
友情链接:
gitHub_Demo
多线程(一)
多线程(二)
多线程(四)