方案 | 简介 | 语言 | 线程生命周期 | 使用频率 |
---|---|---|---|---|
pthread | 一套通用的线程API,适用于Unix/Linux/Window等系,跨平台,可移植,使用难度大 | C | 程序员管理 | 几乎不用 |
NSThread | 使用更加面向对象,可直接操作线程对象 | OC | 程序员管理 | 偶尔使用 |
GCD | 旨在代替NSThread等线程技术,充分利用设备的多核 | C | 自动管理 | 经常使用 |
NSOperation | 基于GCD,比GCD多了部分更加简单实用的工能,使用更加面向对象 | OC | 自动管理 | 经常使用 |
pthread_t threadId = NULL;
// c字符串
char *cString = "HelloCode";
/**
pthread_create 创建线程
参数:
1. pthread_t:要创建线程的结构体指针,通常开发的时候,如果遇到 C 语言的结构体,类型后缀 `_t / Ref` 结尾
同时不需要 `*`
2. 线程的属性,nil(空对象 - OC 使用的) / NULL(空地址,0 C 使用的)
3. 线程要执行的`函数地址`
void *: 返回类型,表示指向任意对象的指针,和 OC 中的 id 类似
(*): 函数名
(void *): 参数类型,void *
4. 传递给第三个参数(函数)的`参数`
*/
int result = pthread_create(&threadId, NULL, pthreadTest, cString);
if (result == 0) {
NSLog(@"成功");
} else {
NSLog(@"失败");
}
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
[self performSelectorInBackground:@selector(run:) withObject:nil];
@property (class, readonly, strong) NSThread *currentThread;
+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
+ (BOOL)isMultiThreaded;
@property (readonly, retain) NSMutableDictionary *threadDictionary;
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
+ (void)exit;
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
@property double threadPriority API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); // To be deprecated; use qualityOfService below
@property NSQualityOfService qualityOfService API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)); // read-only after the thread is started
@property (class, readonly, copy) NSArray<NSNumber *> *callStackReturnAddresses API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (class, readonly, copy) NSArray<NSString *> *callStackSymbols API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property NSUInteger stackSize API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (readonly) BOOL isMainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (class, readonly) BOOL isMainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // reports whether current thread is main
@property (class, readonly, strong) NSThread *mainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (instancetype)init API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
@property (readonly, getter=isExecuting) BOOL executing API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (readonly, getter=isFinished) BOOL finished API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (readonly, getter=isCancelled) BOOL cancelled API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)cancel API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)start API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)main API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // thread body method
// 创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
// 开始执行
[operation start];
// 创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
// 开始任务
[operation start];
// 创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
// 添加多个Block
for (int i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%d次:%@", i, [NSThread currentThread]);
}];
}
// 开始任务
[operation start];
2021-03-23 21:43:11.967090+0800 多线程[32490:7176005] 第4次:<NSThread: 0x6000013fb500>{
number = 7, name = (null)}
2021-03-23 21:43:11.967090+0800 多线程[32490:7176006] 第0次:<NSThread: 0x600001398400>{
number = 4, name = (null)}
2021-03-23 21:43:11.967090+0800 多线程[32490:7176013] 第1次:<NSThread: 0x600001398980>{
number = 5, name = (null)}
2021-03-23 21:43:11.967090+0800 多线程[32490:7175868] <NSThread: 0x6000013cc780>{
number = 1, name = main}
2021-03-23 21:43:11.967099+0800 多线程[32490:7176004] 第2次:<NSThread: 0x600001386e00>{
number = 6, name = (null)}
2021-03-23 21:43:11.967102+0800 多线程[32490:7176008] 第3次:<NSThread: 0x60000138b040>{
number = 3, name = (null)}
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSBlockOperation addExecutionBlock:]: blocks cannot be added after the operation has started executing or finished'
NSOperationQueue *queue = [NSOperationQueue mainQueue];
// 创建一个其他队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
// 添加多个Block
for (int i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%d次:%@", i, [NSThread currentThread]);
}];
}
// 队列添加任务
[queue addOperation:operation];
当多个线程同时访问一块资源时,容易引发数据错乱和数据安全问题,这个时候就需要互斥锁(即同步锁)和自旋锁来解决了。
@property (nonatomic, strong) NSString *target;
dispatch_queue_t queue = dispatch_queue_create("parallel", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 1000000 ; i++) {
dispatch_async(queue, ^{
self.target = [NSString stringWithFormat:@"%d",i];
});
}
任何事情都有两面性,就像多线程能提升效率的同时,也会造成资源竞争的问题。而锁在保证多线程的数据安全的同时,粗心大意之下也容易发生问题,那就是死锁。
NSOperationQueue
NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"lock 1 start");
[NSThread sleepForTimeInterval:1];
NSLog(@"lock 1 over");
}];
NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"lock 2 start");
[NSThread sleepForTimeInterval:1];
NSLog(@"lock 2 over");
}];
NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"lock 3 start");
[NSThread sleepForTimeInterval:1];
NSLog(@"lock 3 over");
}];
// 循环从属
[blockOperation2 addDependency:blockOperation1];
[blockOperation3 addDependency:blockOperation2];
[blockOperation1 addDependency:blockOperation3];
// 互相从属
[blockOperation1 addDependency:blockOperation2];
[blockOperation2 addDependency:blockOperation1];
NSOperationQueue *operationQueue = [NSOperationQueue mainQueue];
NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"lock 1 start");
[NSThread sleepForTimeInterval:1];
NSLog(@"lock 1 over");
}];
NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"lock 2 start");
[NSThread sleepForTimeInterval:1];
NSLog(@"lock 2 over");
}];
NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"lock 3 start");
[NSThread sleepForTimeInterval:1];
NSLog(@"lock 3 over");
}];
[operationQueue addOperation:blockOperation1];
[operationQueue addOperation:blockOperation2];
[operationQueue addOperation:blockOperation3];
GCD
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"task start");
[NSThread sleepForTimeInterval:1.0];
NSLog(@"task over");
});
dispatch_queue_t queue = dispatch_queue_create("sync", DISPATCH_QUEUE_SERIAL);
// 此处异步同样会造成互相等待
dispatch_sync(queue, ^{
NSLog(@"task 1 start");
dispatch_sync(queue, ^{
NSLog(@"task 2 start");
[NSThread sleepForTimeInterval:1.0];
NSLog(@"task 2 over");
});
NSLog(@"task 1 over");
});
dispatch_queue_t queue = dispatch_queue_create("asyn", DISPATCH_QUEUE_SERIAL);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(queue, ^{
__block NSString *str = @"YDW"; // 线程1 创建数据
dispatch_async(queue, ^{
str = [NSString stringWithFormat:@"%ld",[str hash]]; // 线程2 加工数据
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"%@",str); // 线程1 使用加工后的数据
});
if (!_lock) _lock = [NSLock new];
dispatch_queue_t queue = dispatch_queue_create("sync", DISPATCH_QUEUE_CONCURRENT);
[_lock lock];
dispatch_sync(queue, ^{
[_lock lock];
[NSThread sleepForTimeInterval:1.0];
[_lock unlock];
});
[_lock unlock];
主线程环境中,在主队列上执行同步任务,为什么会死锁?
// 任务1
// do something in task1
// 主线程环境中
dispatch_sync(dispatch_get_main_queue(), ^{
// 任务2
// do something in task2
});
主线程环境中,为什么在新创建的串行队列中执行同步任务就不会死锁?
// 任务1
// do something in task1
// 主线程环境中
dispatch_queue_t queue = dispatch_queue_create("YDW", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
// 任务2
// do something in task2
});