1. 基础概念
1.1进程:一个运行的应用程序,就是一个进程(比如:你iphone上的QQ,微信,MAC电脑上的迅雷,Xcode等)
- 每一个进程之间是相互独立的,在内存中开辟空间
- 一个打开应用程序不一定是一个进程(比如:QQ程序,你开启多个QQ账号登录,就
对应的多个进程)
线程:一个进程要执行任务的片段,一条进程至少要有一个线程
- 一个应用程序的所有任务都要在
线程中执行
多线程:是一个进程开启了多条线程,每条线程同时执行不同的任务
主线程
- iOS程序运行之后,默认开启一条线程,成为主线程或者UI线程
- 主线程是用来:刷新UI界面,处理UI事件
使用分类
| 技术 | 简介 | 语言 | 周期 |
|---|---|---|---|
| NSThread | [1]面向对象 [2]可直接操作线程 | OC | 程序员自己管理 -> 偶尔使用 |
| GCD | [1]代替NSThread 【2】充分利用CPU多核 | C | 程序员自己管理 -> 使用次数频繁 |
| NSOperation | [1]基于GCD 【2】面向对象操作 | OC | 程序员自己管理 -> 使用次数频繁 |
2.NSThread 线程
2.1基础认知
- 获取主线程
NSThread *main = [NSThread mainThread];
NSLog(@"%@",main);
- 获取当前线程
//获取当前线程
NSThread *current = [NSThread currentThread];
NSLog(@"-----%@",current);
- 设置线程的名称属性
name属性 - 设置线程的优先级
threadPriority属性,范围0.0-1.0 (默认是0.5)
2.2创建子线程 方法一
//开启一个线程
- (void)setupTh {
/*
*参数一:目标对象
* 参数二:要执行的g方法
* 参数三:要执行的方法需要传入的参数值
*/
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction:) object:@"test"];
//设置线程的名称
thread.name = @"CC";
//启动线程
[thread start];
}
//要执行的方法
- (void)handleThreadAction:(NSString *)par {
NSLog(@"---%@----%@",[NSThread currentThread],par);
}
//打印结果
---<NSThread: 0x600003495fc0>{number = 3, name = CC}----test
2.3 创建子线程 方法二
- (void)setupTwo {
//参数和 方法一的参数 类似
[NSThread detachNewThreadSelector:@selector(handleThreadAction:) toTarget:self withObject:@"text"];
}
- (void)handleThreadAction:(NSString *)par {
NSLog(@"---%@----%@",[NSThread currentThread],par);
NSLog(@"%@",[NSThread isMainThread] == YES ? @"是" :@"不是");
}
//打印
---<NSThread: 0x6000004da8c0>{number = 3, name = (null)}----text
06-03 16:26:23.173228+0800 01-线程[20338:241267] 不是
3. 隐式线程
- (void)setupThress {
//开启一个后台子线程
//这个方法的参数 和 上面创建子线程的类似
[self performSelectorInBackground:@selector(handleThreadAction:) withObject:@"创建放大--"];
}
- (void)handleThreadAction:(NSString *)par {
NSLog(@"---%@----%@",[NSThread currentThread],par);
NSLog(@"%@",[NSThread isMainThread] == YES ? @"是" :@"不是");
}
NSThread线程的生命周期是,当任务执行完成才后被释放这个对象
4.线程的安全问题
出现这个问题的原因,一般为多人同时访问的
共有资源的时候,会导致资源的覆盖或者资源数据出错(比如:售票)
4.1互斥(同步)锁
@synchronized ("全局属性") {
//要枷锁的代码
}
- 互斥锁的条件
- 必须是全局
唯一的对象 - 多线程
共享同一块资源
- 必须是全局
- 互斥锁的结果
- 线程同步执行
- 耗费性能
- (void)saleoftickets{
self.read1 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
self.read2 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
self.read3 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
self.read1.name = @"售票TT";
self.read2.name = @"售票CC";
self.read3.name = @"售票BB";
//启动线程
[self.read1 start];
//启动线程
[self.read2 start];
//启动线程
[self.read3 start];
}
//执行方法
- (void)handleThreadAction{
// synchronized 是消耗性能的,线程使用的锁对象 必须是同一个对象
// 可以定义一个属性对象
while (1) {
@synchronized (self) {
for (int i = 0; i < 1000; i ++) {
}
NSUInteger accunt = self.acount;
if (accunt > 0) {
self.acount = accunt - 1;
NSLog(@"%@----%ld",[NSThread currentThread].name,self.acount);
}else {
NSLog(@"售完了。。。。");
break;
}
}
}
}
4.2原子属性和非原子属性
nonatomic非原子属性,没有加互斥锁atomic原子属性,为了线程安全,在setter加互斥锁
5.线程之间的通信
- 线程之间通信常用的方法
//在子线程中调用 这个方法 就是回到主线程 进行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait
// 从一个线程跳转到另外一个线程执行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
主要用于:图片下载异步操作
6.线程阻塞
- (void)sleepThread {
//阻塞2秒
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
//阻塞到遥远的未来
[NSThread sleepUntilDate:[NSDate distantFuture]];
}
本文深入探讨了iOS应用中的多线程技术,包括进程与线程的基础概念、NSThread的使用方法、线程间的通信机制、线程安全问题及解决策略。通过实例展示了如何创建子线程,解释了主线程的作用,并讨论了线程阻塞的概念。
1326

被折叠的 条评论
为什么被折叠?



