iOS多线程之Pthread/NSthread
来源:互联网 发布:ubuntu下安装jdk 编辑:程序博客网 时间:2024/05/16 05:10
要学习多线程的知识首先要了解一些多线程的基本知识,什么是线程,进程,多线程原理,多线程优缺点等。下面是多线程的基础知识
多线程基础知识
进程
进程是指在系统中正在运⾏行的一个应用程序
每个进程之间是独⽴的,每个进程均运⾏在其专用且受保护的内存空间内
线程
一个进程要想执⾏任务,必须得有线程(每1个进程⾄少要有1条线程)
线程是进程的基本执⾏单元,一个进程(程序)的所有任务都在线程中执⾏
- 进程负责开辟内存空间
- 线程负责执行任务
线程的串⾏(排排坐,吃果果,你一个,我一个)
一个线程中任务的执⾏是串⾏(顺序执⾏)的
如果要在一个线程中执⾏多个任务,那么只能⼀个⼀个地按顺序执⾏行这些任务
也就是说,在同⼀时间内,一个线程只能执⾏一个任务
多线程
一个进程中可以开启多条线程,每条线程可以并发(同时)执⾏不同的任务
多线程技术可以提⾼高程序的执⾏行效率
多线程的原理
同⼀时间,CPU只能处理一条线程,只有一条线程在⼯作(执⾏)。多线程并发(同时)执⾏,其实是CPU快速地在多条线程之间调度(切换), 如果CPU调度线程的时间⾜够快,就造成了多线程并发执⾏的假象。如果线程非常多,CPU会在N多线程之间调度,CPU会累死,消耗⼤大量的CPU资源。
多线程的优点
● 能适当提高程序的执行效率,开启新应用能立刻执行,不需要等之前的运行完毕。
● 能适当提高资源利用率(CPU、内存利⽤用率)
多线程的缺点
● 开启线程需要占用一定的内存空间(默认情况下,每一条线程都占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
● 线程越多,CPU在调度线程上的开销就越大
● 程序设计更加复杂:比如线程之间的通信、多线程的数据共享
主线程
一个IOS程序运行后,默认会开启一条线程,称为“主线程”或者“UI”线程。
主线程的作用:主要是显示和刷新UI界面,处理UI的操作事件
主线程注意:不要将耗时的操作放到主线程中,因为耗时的会一直占用主线程,导致UI的滚动,拖拽,点击事件不能被处理,影响UI的流畅度,出现“卡顿”现象,导致用户体验不佳。所以一般将耗时操作放在子线程中进行
[NSThread currentThread]
可以在所有的多线程技术中使用
打印当前线程3
[NSThread currentThread]
通常用来在多线程开发中,判断是否在主线程
number == 1 说明是主线程
number != 1 说明是其他线程
IOS多线程方案
实例化:pthread
// 创建线程 // C语言中类型的结尾通常 _t/Ref,而且不需要使用 * pthread_t threadId; NSString *str = @"Hello Pthread"; int result = pthread_create(&threadId, NULL, &demo, (__bridge void *)(str)); /* 在其他线程执行 demo 函数 返回int类型的数值 参数 1. 线程代号的地址 2. 线程的属性 3. 调用函数的指针 4. 传递给该函数的参数 返回值 - 如果是0,表示正确 - 如果是非0,表示错误码 */ if (result == 0) { NSLog(@"OK"); } else { NSLog(@"error %d", result); }}void *demo(void *param) { NSString *sss = (__bridge NSString *)(param); NSLog(@"%@, %@", [NSThread currentThread], sss); return NULL;}
void * 和 OC 中的 id 是等价的
id(*)(id)
- 在 ARC 开发中,如果设计到和 C 语言中相同的数据类型进行转换时,需要使用 __bridge “桥接”
在 MRC 开发中,不需要桥接
在 OC 中,如果是 ARC 开发,编译器会在编译的时候,自动根据代码结构,添加 retain, release, autorelease
ARC 只负责 OC 部分的代码,不负责 C 的代码,如果 C 语言的框架出现 retain/create/copy 字样的函数,都需要release关于桥接的添加,可以利用 Xcode 辅助实现!
实例化:NSthread
主要语句:
// 创建线程,运行demo方法1、NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@"Thread"]; // 启动线程 [thread start];2、[NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"Detach"];3、[self performSelectorInBackground:@selector(demo:) withObject:@"background"];@implementation ViewController- (void)viewDidLoad { [super viewDidLoad];}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self threadDemo3_1];}// NSThread 创建//=====================================================================- (void)threadDemo3_1 { Person *p = [[Person alloc] init]; [p performSelectorInBackground:@selector(loadData) withObject:nil];}//============================- (void)threadDemo3 { // 打印当前是在那个线程 NSLog(@"1--%@", [NSThread currentThread]); // 是 NSObject 的一个分类方法,意味着所有的 NSObject 都可以使用此方法,在其他线程执行方法! // 特点:没有thread字眼,一旦制定,就会立即在后台线程执行 selector 方法 // performSelectorInBackground 隐式的多线程方法 // 这种方法,在使用的时候更加灵活! [self performSelectorInBackground:@selector(demo:) withObject:@"background"]; NSLog(@"2--%@", [NSThread currentThread]);}//=====================================================================- (void)threadDemo2 { // 1 NSLog(@"1--%@", [NSThread currentThread]); // detachNewThreadSelector 会立即在后台线程执行 selector 方法,不需要手动star // detach => 分离一个子线程执行 demo: 方法 [NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"Detach"]; // 1/2? NSLog(@"2--%@", [NSThread currentThread]);}//=====================================================================- (void)threadDemo1 { NSLog(@"1-------"); // 实例化线程/加载 => alloc(分配内存) / init(初始化) NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@"Thread"]; // 启动线程 [thread start]; // 在线程1 输出 NSLog(@"2------- %@", [NSThread currentThread]);}- (void)demo:(id)obj { for (int i = 0; i<2; i++) { NSLog(@"%@ %@", [NSThread currentThread], obj); }}@end
NSthread的属性
线程的名字:在大的商业项目中,通常希望程序崩溃的时候,能够获取到程序准确执行所在的线程!
线程优先级:优先级只是保证 CPU 调度的可能性会高,一般不设置优先级
NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil]; t1.name = @"Thread A"; // name 在大得项目中,能够准确获取程序执行所在的线程 // 优先级,是一个浮点数,从0~1.0,1.0表示优先级最高,默认优先级是0.5 t1.threadPriority = 0.1; [t1 start];
线程的状态
新建:NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(threadStatus) object:nil];
放在可调度线程池中
就绪:[t start];
放在可调度线程池中
运行:NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(threadStatus) object:nil];
阻塞(睡一会儿):[NSThread sleepForTimeInterval:2.0];
从可调度线程池中移出
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
从现在开始睡多久
死亡:[NSThread exit]
一般不要在主线程里面玩这个东东,在子线程中玩的时候,先做一个判断。exit之前要释放对象,因为Arc会清楚OC对象,
但是C的对象要手动清除。
多线程的安全隐患
互斥锁 - 保证锁内的代码,同一时间,只有一条线程能够执行!
利用互斥锁 防止把同一张车票卖给两个人
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { self.tickets = 20; NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil]; t1.name = @"售票员 A"; [t1 start]; NSThread *t2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil]; t2.name = @"售票员 B"; [t2 start];}// MARK: - 卖票逻辑/** 在开发多线程程序时,按照以下步骤 1. 保证单个线程执行正常! 2. 每一个售票逻辑(窗口)应该把所有的票卖完 3. 添加线程 */- (void)saleTickets { while (YES) { // 模拟休眠 [NSThread sleepForTimeInterval:1.0]; // 注意,锁一定要是所有线程共享的对象,不能是对象里面的一个局部变量(上厕所自己兜里的锁) // 如果代码中只有一个地方需要加锁,大多都使用 self // 互斥锁 - 保证锁内的代码,同一时间,只有一条线程能够执行! // 要锁住关键的操作,锁定范围越小,效率越高 @synchronized(self) { // self就是加锁的对象,不能局部变量,能够加锁任意的NSObject对象 if (self.tickets > 0) { self.tickets--; NSLog(@"剩余票数 %d %@", self.tickets, [NSThread currentThread]); } else { NSLog(@"没有票了 %@", [NSThread currentThread]); break; } } }}
原子属性
- nonatomic: 非原子属性(多线程,高效)
- atomic: 原子属性(线程安全),就是针对多线程设计的,是默认属性
多个线程写入属性时,保证同一时间只有一个线程能够执行写入操作
单(线程)写多(线程)读的一种多线程技术,同样有可能出现“脏数据 (错误数据)”,重新读一下。
实际上,原子属性内部也有一把锁,自旋锁
自旋锁 & 互斥锁
- 共同点
都能够保证同一时间,只有一条线程执行锁定范围的代码 不同点
- 互斥锁:如果发现有其他线程正在执行锁定的代码,线程会进入休眠状态,等待其他线程执行完毕,打开锁之后,线程会被唤醒
- 自旋锁:如果发现有其他线程正在执行锁定的代码,线程会用死循环的方式,一直等待锁定代码执行完成!
自旋锁更适合执行非常短的代码!无论什么锁,都是要付出代价的!多线程是追求效率,有锁安全,但是效率低
线程安全
在多个线程进行读写操作时,仍然能够保证数据正确!效率不高!
UI 线程,共同约定:所有更新 UI 的操作都在主线程上执行!
原因:几乎所有的 UIKit 都不是线程安全的!”考虑到效率,只能这样取舍”
日常开发中,使用锁的机会很少,多线程的目的,就是将耗时的操作放在后台!
- iOS多线程之Pthread/NSthread
- iOS多线程之Pthread/NSthread
- iOS多线程之Pthread/NSthread
- iOS多线程--彻底学会多线程之『pthread、NSThread』
- iOS多线程--彻底学会多线程之『pthread、NSThread』
- iOS中多线程的实现方案之pthread和NSThread
- iOS中的多线程技之Pthread和NSThread
- iOS-多线程之Pthread、NSThread实例和理解
- iOS多线程之NSThread
- ios多线程之NSThread
- iOS多线程之NSThread
- iOS多线程之NSThread
- iOS 多线程之NSThread
- IOS多线程之NSThread
- iOS --- 多线程之NSThread
- iOS多线程之NSThread
- iOS多线程之NSThread
- iOS多线程之NSThread
- Android 深入解析AsyncTask(doInBackground不工作)
- iterator标签用begin属性报错:Attribute var invalid for tag iterator according to TLD
- NSThread创建多线程
- 黑马程序员------ios培训 oc内存管理(二)
- [openCV]图像的傅里叶频谱
- iOS多线程之Pthread/NSthread
- Cocos2d-x Lua中网格动作
- 图片连接效果的制作
- Android 竖直排列显示两个ListView
- Android edittext 显示字数限制和输入类型
- gdi/gdiplus如何加载字体
- idea中进行运行时报错:cannot start compilation the output path is not specified for module
- 用什么软件可以编辑pdf文件
- 仿360图集效果的制作