线程状态/互斥锁/通信
标签(空格分隔): 多线程
线程的5种状态
- 新建、就绪、运行、阻塞、死亡
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// 线程的新建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
// 线程开始(start)
[thread start];
NSLog(@"开始执行子线程");
}
- (void)run{
for (int i = 0 ; i< 50; i++) {
NSLog(@"%d",i);
if (i % 5 == 0) {
// 让线程休息2秒(阻塞)
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
NSLog(@"线程正在休息");
if (i == 30) {
// 结束线程(死亡)
NSLog(@"子线程挂了");
[NSThread exit];
/*简单粗暴地结束方式:return;*/
}
}
}
}
互斥锁/线程同步(@synchronized(对象))
用途:为了解决一块资源被多个线程共享造成的
数据紊乱
和数据安全
问题只要被
@synchronized的{}
包裹起来的代码,同一时刻就只能被一个线程执行
- 注意:
- 只要枷锁就会消耗性能
- 加锁必须
传递一个对象
, 作为锁(一般都是传self) - 如果想真正的锁住代码,那么多个线程必须
使用同一把锁
才行 - 加锁的时候尽量
缩小范围
, 因为范围越大性能就越低
原子和非原子属性
atomic
:原子属性,为setter方法加锁(默认就是atomic)nonatomic
:非原子属性,不会为setter方法加锁对比
- atomic:线程安全,需要消耗大量的资源
- nonatomic:非线程安全,适合内存小的移动设备
注意点
atomic系统自动给我们添加的锁不是互斥锁(而是自旋锁)
互斥锁和自旋锁
共同点
- 都能够保证多线程在同一时候,只能有一个线程操作锁定的代码
- 互斥锁和自旋锁
不同点
- 如果是互斥锁,假如现在被锁住了,那么后面来得线程就会进入”休眠”状态, 直到解锁之后, 又会唤醒线程继续执行
- 如果是自旋锁,假如现在被锁住了,那么后面来得线程不会进入休眠状态, 会一直傻傻的等待, 直到解锁之后立刻执行
- 自旋锁更适合做一些较短的操作
- 尽量避免多线程抢夺同一块资源,尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
线程间通信
- 1个线程传递数据给另1个线程
- 在1个线程中执行完特定任务后,转到另1个线程继续执行任务
- 常用方法:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
// waitUntilDone的含义:
如果传入的是YES: 那么会等到主线程中的方法执行完毕, 才会继续执行下面其他行的代码
如果传入的是NO: 那么不用等到主线程中的方法执行完毕, 就可以继续执行下面其他行的代码
- 从子线程回到主线程(加入主队列)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// 穿件队列,获取全局并行队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 添加下载任务到子线程中
dispatch_async(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
// 下载图片
NSURL *url = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/1b4c510fd9f9d72aee889e1fd22a2834359bbbc0.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 显示UI控件,将此任务加入到主队列中
// 如果是通过异步函数添加任务,会先执行完所有代码再来执行block中的任务
// 如果是通过同步函数添加的任务,会先执行完block中的任务再执行其他代码
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSThread currentThread]);
self.imageView.image = image;
});
});
}