^_^嗨一下
文章目录
  1. 简介
  2. 启动方式
  3. 线程通讯
  4. 线程同步

简介

iOS有三种多线程编程的技术分别是NSThread 、Cocoa NSOperation、GCD,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。在前面呢我对GCD的基本使用做过一些简单的总结,大家有空可以看看。这里呢我主要对NSThread的一些基本的使用呢做一些基本的概括。主要是对自己进行一些总结,也希望对大家使用NSThread的开发者有用。

NSThread相比其他两个的用法呢,最大的差别就是我们要对我们做的事情负责,简单来说就是我们用了它,就得需要自己管理thread的生命周期,线程之间的同步也需要自己手动添加代码,其实呢也没那么麻烦的哈,不要被吓到了。从事过java开发的人来说呢thread就更好理解了,因为他们是完全类似的。是不是已经迫不及待了,那我们就进入正题吧。

启动方式

1、显式启动

1
2
3
4
5
6
7
//NSThread的创建主要有两种直接方式:
[NSThread detachNewThreadSelector:@selector(todoMethod:) toTarget:self withObject:nil];
NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(todoMethod:)
object:nil];
[myThread start];

这两种方式的区别是:前一种一调用就会立即创建一个线程来做事情;而后一种虽然你 alloc 了也 init了,但是要直到我们手动调用 start 启动线程时才会真正去创建线程。
这种延迟实现思想在很多跟资源相关的地方都有用到。后一种方式我们还可以在启动线程之前对线程 进行配置比如设置stack大小,给它取个名字啊什么的还有设置线程优先级都是很方便的。

2、隐式启动

1
[myObj performSelectorInBackground:@selector(myThreadMainMethod) withObject:nil];

利用 NSObject 的类方法直接就创建了个线程,是不是更加的方便了,但是他的效果和detachNewThreadSelector:toTarget:withObject:是一样的。

线程通讯

NSThread线程通讯提供了很多的方法,包括获取主线程、子线程之间进行通讯、操作当前线程、取消发送给当前线程的消息等等
这里我只举每个地方使用所用到的几个方法
在应用程序主线程 中做事情:
performSelectorOnMainThread:withObject:waitUntilDone:
performSelectorOnMainThread:withObject:waitUntilDone:modes:

在指定 线程 中做事情: 
performSelector:onThread:withObject:waitUntilDone: 
performSelector:onThread:withObject:waitUntilDone:modes: 

在当前 线程 中做事情: 
performSelector:withObject:afterDelay: 
performSelector:withObject:afterDelay:inModes: 

取消发送给当前 线程 的某个消息 
cancelPreviousPerformRequestsWithTarget: 
cancelPreviousPerformRequestsWithTarget:selector:object: 

eg:[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO]搞定,使用起来很方便。

线程同步

涉及到同步操作呢,学java的同学应该就不陌生了,那就是使用锁。NSThread提供了很多类型的锁NSLock、NSCondition、循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock。其中呢NSLock、NSCondition是比较常用的锁。
看个例子吧[参考 iOS多线程编程之NSThread的使用](http://blog.csdn.net/totogo2010/article/details/8010231)
NSThread的线程同步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import <UIKit/UIKit.h>
@class ViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
int tickets;
int count;
NSThread* ticketsThreadone;
NSThread* ticketsThreadtwo;
NSCondition* ticketsCondition;
NSLock *theLock;
}
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) ViewController *viewController;
@end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
tickets = 100;
count = 0;
theLock = [[NSLock alloc] init];
// 锁对象
ticketsCondition = [[NSCondition alloc] init];
ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadone setName:@"Thread-1"];
[ticketsThreadone start];
ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadtwo setName:@"Thread-2"];
[ticketsThreadtwo start];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)run{
while (TRUE) {
// 上锁
// [ticketsCondition lock];
[theLock lock];
if(tickets >= 0){
[NSThread sleepForTimeInterval:0.09];
count = 100 - tickets;
NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
tickets--;
}else{
break;
}
[theLock unlock];
// [ticketsCondition unlock];
}
}

加上锁后呢线程使用就安全了很多,不会出现票被多卖了的情况,加上lock之后线程同步保证了数据的正确性,这里没有要求线程的顺序,所以NSCondition可以去掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#import "AppDelegate.h"
#import "ViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
tickets = 100;
count = 0;
theLock = [[NSLock alloc] init];
// 锁对象
ticketsCondition = [[NSCondition alloc] init];
ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadone setName:@"Thread-1"];
[ticketsThreadone start];
ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[ticketsThreadtwo setName:@"Thread-2"];
[ticketsThreadtwo start];
NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];
[ticketsThreadthree setName:@"Thread-3"];
[ticketsThreadthree start];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
-(void)run3{
while (YES) {
[ticketsCondition lock];
[NSThread sleepForTimeInterval:3];
[ticketsCondition signal];
[ticketsCondition unlock];
}
}
- (void)run{
while (TRUE) {
// 上锁
[ticketsCondition lock];
[ticketsCondition wait];
[theLock lock];
if(tickets >= 0){
[NSThread sleepForTimeInterval:0.09];
count = 100 - tickets;
NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
tickets--;
}else{
break;
}
[theLock unlock];
[ticketsCondition unlock];
}
}

[ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。wait是等待,我加了一个 线程3 去唤醒其他两个线程锁中的wait

其实为了简化NSLock的使用我们还可以使用到synchronized 关键字,这个学过java的人来说又是再熟悉不过的了。

1
2
3
4
5
6
7
- (void)doSomeThing:(id)anObj
{
@synchronized(anObj)
{
// to do something
}
}

文章目录
  1. 简介
  2. 启动方式
  3. 线程通讯
  4. 线程同步