【多线程】NSThread

2018-06-10  本文已影响10人  大基本功

1️⃣创建和启动线程简单说明

一个NSThread对象就代表一条线程

创建、启动线程
 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
// 线程一启动,就会在线程thread中执行self的run方法
主线程相关用法
+ (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; // 是否为主线程
+ (BOOL)isMainThread; // 是否为主线程
其他用法
//获得当前线程
NSThread *current = [NSThread currentThread];
//线程的调度优先级:调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
//设置线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;

创建线程后自动启动线程

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
//  隐式创建并启动线程  
[self performSelectorInBackground:@selector(run) withObject:nil];
//上述2种创建线程方式的优缺点
//优点:简单快捷
//缺点:无法对线程进行更详细的设置

2️⃣线程安全

一、多线程的安全隐患

资源共享

示例一:

示例二:

问题代码:

#import "YYViewController.h"
11 
12 @interface YYViewController ()
13 //剩余票数
14 
15 @property(nonatomic,assign) int leftTicketsCount;
16 @property(nonatomic,strong)NSThread *thread1;
17 @property(nonatomic,strong)NSThread *thread2;
18 @property(nonatomic,strong)NSThread *thread3;
19 
20 
21 @end
22 
23 
24 @implementation YYViewController
25 
26 
27 - (void)viewDidLoad
28 {
29     [super viewDidLoad];
30 
31     //默认有20张票
32 
33     self.leftTicketsCount=10;
34 
35     //开启多个线程,模拟售票员售票
36 
37     self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
38 
39     self.thread1.name=@"售票员A";
40 
41     self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
42 
43     self.thread2.name=@"售票员B";
44 
45     self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
46     self.thread3.name=@"售票员C";
47 }
48 
49  
50 -(void)sellTickets
51 {
52     while (1) {
53         //1.先检查票数
54         int count=self.leftTicketsCount;
55         if (count>0) {
56             //暂停一段时间
57             [NSThread sleepForTimeInterval:0.002];
58 
59             //2.票数-1
60            self.leftTicketsCount= count-1;
61  
62             //获取当前线程
63             NSThread *current=[NSThread currentThread];
64             NSLog(@"%@--卖了一张票,还剩余%d张票",current,self.leftTicketsCount);
65         }else
66         {
67             //退出线程
68             [NSThread exit];
69         }
70     }
71 }
72 
73 
74 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
75 { 
76     //开启线程
77 
78    [self.thread1 start];
79     [self.thread2 start];
80     [self.thread3 start];
81 
82 }
83 
84 @end

打印结果:

image
二、安全隐患分析
三、如何解决
43 -(void)sellTickets
44 {
45     while (1) {
46         @synchronized(self){//只能加一把锁
47         //1.先检查票数
48 
49         int count=self.leftTicketsCount;
50         if (count>0) {
51             //暂停一段时间
52             [NSThread sleepForTimeInterval:0.002];
53             //2.票数-1
54 
55            self.leftTicketsCount= count-1;
56             //获取当前线程
57             NSThread *current=[NSThread currentThread];
58             NSLog(@"%@--卖了一张票,还剩余%d张票",current,self.leftTicketsCount);
59 
60         }else
61         {
62             //退出线程
63             [NSThread exit];
64         }
65         }
66     }
67 }

执行效果图


互斥锁的优缺点
四:原子和非原子属性
1 @property (assign, atomic) int age;
2 
3 - (void)setAge:(int)age
4 { 
5 
6     @synchronized(self) { 
7        _age = age;
8     }
9 }
原子和非原子属性的选择
iOS开发的建议

3️⃣线程间通信

线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信

线程间通信的体现

1个线程传递数据给另1个线程

在1个线程中执行完特定任务后,转到另1个线程继续执行任务

线程间通信常用方法

线程间通信示例 – 图片下载

12 @interface YYViewController ()
13 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
14 @end
15 
16 @implementation YYViewController
17 
18 - (void)viewDidLoad
19 {
20     [super viewDidLoad];
21 }
22 
23  
24 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
25 {
26 // 在子线程中调用download方法下载图片
27 
28     [self performSelectorInBackground:@selector(download) withObject:nil];
29 }
30 
31  
32 -(void)download
33 {
34 
35     //1.根据URL下载图片
36     //从网络中下载图片
37     NSURL *urlstr=[NSURL URLWithString:@"fdsf"];
38 
39     //把图片转换为二进制的数据
40     NSData *data=[NSData dataWithContentsOfURL:urlstr];//这一行操作会比较耗时
41 
42     //把数据转换成图片
43     UIImage *image=[UIImage imageWithData:data];
44 
45     //2.回到主线程中设置图片
46     //第一种方式
47 //    [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
48 
49     //第二种方式
50     //    [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
51 
52     //第三种方式
53    [self.iconView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
54 }
55 
56 
57 //设置显示图片
58 //-(void)settingImage:(UIImage *)image
59 //{
60 //    self.iconView.image=image;
61 //}
62 
63 @end

参考

上一篇下一篇

猜你喜欢

热点阅读