#import "ViewController.h"
@interface ViewController ()
@property (assign, nonatomic) int ticketCount;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置初始值
self.ticketCount = 10;
}
- (void)saleTicket
{
int oldTicket = self.ticketCount;
sleep(.2);// 为了使多线程安全问题更加突出明显
oldTicket--;
self.ticketCount = oldTicket;
NSLog(@"还剩%d张票,-%@",oldTicket,[NSThread currentThread]);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 1 异步并发队列 (执行过程,(任务同步执行)执行的每一个任务都可能是开启新的不同的线程,出现多线程安全隐患问题)
/*
2018-11-09 08:10:57.504969+0800 MultiThread[4165:33899] 还剩7张票,-<NSThread: 0x604000275480>{number = 5, name = (null)}
2018-11-09 08:10:57.505043+0800 MultiThread[4165:33900] 还剩6张票,-<NSThread: 0x604000267fc0>{number = 6, name = (null)}
2018-11-09 08:10:57.505131+0800 MultiThread[4165:33894] 还剩9张票,-<NSThread: 0x600000274e80>{number = 3, name = (null)}
2018-11-09 08:10:57.505157+0800 MultiThread[4165:33392] 还剩8张票,-<NSThread: 0x604000268f80>{number = 4, name = (null)}
*/
// [self saleTicketsByAsyncConcurrentQueue];
// 2(1) 同步并发队列 (执行过程,(任务依次执行)执行的每一个任务都是在主线程执行(创建新的线程的话,在新的这个子线程中执行),不会出现线程安全隐患问题)
/*
2018-11-09 08:14:09.411497+0800 MultiThread[4513:36117] 还剩9张票,-<NSThread: 0x60000007e3c0>{number = 1, name = main}
2018-11-09 08:14:09.413190+0800 MultiThread[4513:36117] 还剩8张票,-<NSThread: 0x60000007e3c0>{number = 1, name = main}
2018-11-09 08:14:09.413855+0800 MultiThread[4513:36117] 还剩7张票,-<NSThread: 0x60000007e3c0>{number = 1, name = main}
2018-11-09 08:14:09.414058+0800 MultiThread[4513:36117] 还剩6张票,-<NSThread: 0x60000007e3c0>{number = 1, name = main}
*/
// [self saleTicketsBySyncConcurrrentQueue];
// 2(2) 同步并发队列 (执行过程,(任务依次执行)执行的每一个任务都是在新创建这个子线程中执行(没有创建新的线程的话,默认在主线程执行),不会出现线程安全隐患问题)
/*
2018-11-09 08:22:48.043307+0800 MultiThread[5345:43339] 还剩9张票,-<NSThread: 0x600000476940>{number = 3, name = (null)}
2018-11-09 08:22:48.044512+0800 MultiThread[5345:43339] 还剩8张票,-<NSThread: 0x600000476940>{number = 3, name = (null)}
2018-11-09 08:22:48.044892+0800 MultiThread[5345:43339] 还剩7张票,-<NSThread: 0x600000476940>{number = 3, name = (null)}
2018-11-09 08:22:48.045262+0800 MultiThread[5345:43339] 还剩6张票,-<NSThread: 0x600000476940>{number = 3, name = (null)}
*/
// NSThread *mySubThread = [[NSThread alloc]initWithBlock:^{
// [self saleTicketsBySyncConcurrentQueueInSubThread];
// }];
// [mySubThread start];
// 3 异步串行队列 (执行过程,任务依次执行),异步是具备开启线程的能力,所以任务是在新开启的线程中执行的
/*
2018-11-09 08:29:45.335619+0800 MultiThread[5982:48675] 还剩9张票,-<NSThread: 0x604000465900>{number = 3, name = (null)}
2018-11-09 08:29:45.337492+0800 MultiThread[5982:48675] 还剩8张票,-<NSThread: 0x604000465900>{number = 3, name = (null)}
2018-11-09 08:29:45.339066+0800 MultiThread[5982:48675] 还剩7张票,-<NSThread: 0x604000465900>{number = 3, name = (null)}
2018-11-09 08:29:45.339200+0800 MultiThread[5982:48675] 还剩6张票,-<NSThread: 0x604000465900>{number = 3, name = (null)}
*/
// [self saleTicketsByAsyncSerialQueue];
// 4(1) 同步串行队列 (执行过程,默认在主线程中执行,没有开启新的线程),任务依次执行
/*
2018-11-09 08:32:52.110500+0800 MultiThread[6285:50954] 还剩9张票,-<NSThread: 0x60000007db00>{number = 1, name = main}
2018-11-09 08:32:52.111387+0800 MultiThread[6285:50954] 还剩8张票,-<NSThread: 0x60000007db00>{number = 1, name = main}
2018-11-09 08:32:52.112358+0800 MultiThread[6285:50954] 还剩7张票,-<NSThread: 0x60000007db00>{number = 1, name = main}
2018-11-09 08:32:52.112976+0800 MultiThread[6285:50954] 还剩6张票,-<NSThread: 0x60000007db00>{number = 1, name = main}
*/
// [self saleTicketsBySyncSerialQueue];
// 4(2) 同步串行 (执行过程,在新创建的线程中执行,同步没有开启新线程的能力),任务依次执行
/*
2018-11-09 08:34:42.703053+0800 MultiThread[6466:52766] 还剩9张票,-<NSThread: 0x60000026b780>{number = 3, name = (null)}
2018-11-09 08:34:42.703639+0800 MultiThread[6466:52766] 还剩8张票,-<NSThread: 0x60000026b780>{number = 3, name = (null)}
2018-11-09 08:34:42.704769+0800 MultiThread[6466:52766] 还剩7张票,-<NSThread: 0x60000026b780>{number = 3, name = (null)}
2018-11-09 08:34:42.706400+0800 MultiThread[6466:52766] 还剩6张票,-<NSThread: 0x60000026b780>{number = 3, name = (null)}
*/
// NSThread *mySyncSerailQueueInSubThread = [[NSThread alloc]initWithBlock:^{
// [self saleTicketsBySyncSerialQueue];
// }];
// [mySyncSerailQueueInSubThread start];
//
}
#pragma mark - 创建异步并发队列
- (void)saleTicketsByAsyncConcurrentQueue
{
dispatch_queue_t asyncConQueue = dispatch_queue_create("myAsyncConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(asyncConQueue, ^{
[self saleTicket];
});
dispatch_async(asyncConQueue, ^{
[self saleTicket];
});
dispatch_async(asyncConQueue, ^{
[self saleTicket];
});
dispatch_async(asyncConQueue, ^{
[self saleTicket];
});
}
#pragma mark - 创建同步并发队列(未创建新的线程,默认同步并发,是在主线程进行)
- (void)saleTicketsBySyncConcurrrentQueueInMain
{
dispatch_queue_t syncConcurrentQueue = dispatch_queue_create("mySyncConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(syncConcurrentQueue, ^{
[self saleTicket];
});
dispatch_sync(syncConcurrentQueue, ^{
[self saleTicket];
});
dispatch_sync(syncConcurrentQueue, ^{
[self saleTicket];
});
dispatch_sync(syncConcurrentQueue, ^{
[self saleTicket];
});
}
#pragma mark - 创建同步并发队列(创建新的线程,同步并发会在新创建的这个线程中串行执行任务)
- (void)saleTicketsBySyncConcurrentQueueInSubThread
{
dispatch_queue_t syncConcurrentQueueInSubThread = dispatch_queue_create("mySyncConcurrentQueueInSubThread", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(syncConcurrentQueueInSubThread, ^{
[self saleTicket];
});
dispatch_sync(syncConcurrentQueueInSubThread, ^{
[self saleTicket];
});
dispatch_sync(syncConcurrentQueueInSubThread, ^{
[self saleTicket];
});
dispatch_sync(syncConcurrentQueueInSubThread, ^{
[self saleTicket];
});
}
#pragma mark - 创建异步串行队列
- (void)saleTicketsByAsyncSerialQueue
{
dispatch_queue_t asyncSerialQueue = dispatch_queue_create("myAsyncSerialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(asyncSerialQueue, ^{
[self saleTicket];
});
dispatch_async(asyncSerialQueue, ^{
[self saleTicket];
});
dispatch_async(asyncSerialQueue, ^{
[self saleTicket];
});
dispatch_async(asyncSerialQueue, ^{
[self saleTicket];
});
}
#pragma mark - 创建同步串行队列
- (void)saleTicketsBySyncSerialQueue
{
dispatch_queue_t syncSerialQueue = dispatch_queue_create("mySyncSerialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(syncSerialQueue, ^{
[self saleTicket];
});
dispatch_sync(syncSerialQueue, ^{
[self saleTicket];
});
dispatch_sync(syncSerialQueue, ^{
[self saleTicket];
});
dispatch_sync(syncSerialQueue, ^{
[self saleTicket];
});
}
@end
总结
1 引发的问题
异步并发会引起多线程安全隐患问题.
2 问题的解决方案
多线程安全问题的解决方案是:使用线程同步(同步就是按预定的先后次序进行),常用的线程同步技术是加锁
3 锁的类型及其性能比较
- OSSpinLock 自旋锁
- os_unfair_lock
- pthread_mutex
- disptach_semaphare信号量
- disptach_queue(DISPATCH_QUEUE_SERIAL)串行队列
- NSLock
- NSRecursiveLock
- NSCondition
- NSConditionLock
- @synchronized
具体各种类型的锁在下篇文章中讲解