您的位置:首页 > 移动开发 > IOS开发

iOS之多线程---三种多线程技术

2015-10-22 14:32 387 查看
1.多线程的基本概念和用法

①进程:每一个进程都一是一个应用程序,都有独立的内存空间。(一个程序也可以由多个进程)同一个进程中的线程共享内存中的存储空间和资源

②线程:

每一个程序都有一个主线程,调用main来启动。

主线程的生命周期和应用程序绑定,程序退出时主线程停止。

任何可以阻塞主线程的任务不要再主线程中执行(比如访问网络)

2.多线程使用的注意

①线程使用不是无节制的:

iOS中的主线程的堆栈大小是1M(不可变)

从第二个线程开始都是512KB(不可变)

②只有主线程可以修改UI,渲染引擎工作在主线程中

3.IOS的三种多线程技术(本文主题)

①NSThread:每个NSThread对象对应一个线程

优:量级较轻

缺:需要自己管理线程的生命周期、线程同步、加锁、睡眠和唤醒等,

②NSOperation/NSOperationQueue:面向对象的线程技术

优:不需要关心线程管理、数据同步的事情,且是面向对象的

③GCD(Grand Central Dispatch):是基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术

下面对三种技术,用代码逐一讲解:

①NSThread

- (void)viewDidLoad {
[super viewDidLoad];

for (int i=0; i<10; i++) {
//1.线程睡眠
[NSThread sleepForTimeInterval:1];
NSLog(@"主线程1: %d", i);
}

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(thread1:) object:@"multiThread1"];
//2.开始线程
[thread start];

for (int i=0; i<10; i++) {
//3.获取当前线程
NSThread *current = [NSThread currentThread];
//4.判断当前线程是否是主线程
BOOL isMain = [current isMainThread];
if (isMain) {
NSLog(@"主线程2: %d", i);
}
}
}

-(void) thread1:(NSString *) threadName{
for (int i=0; i<10; i++) {
NSLog(@"%@: %d", threadName, i);
if (i == 5) {
//5.退出线程
[NSThread exit];
}
}
}


②NSOperationQueue

- (void)viewDidLoad {
[super viewDidLoad];

//1.创建线程队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

//2.创建线程任务
/*NSOperation介绍:
是Cocoa中的一个抽象类,用来封装单个任务和代码执行一项操作,由于是抽象类,所以不能直接实例化使用,必须定义子类继承该抽象类来实现(常用的为NSInvocationOperation类,但是也可以自己继承重写NSOperation类)
*/
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(thread1:) object:@"thread1"];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(thread2:) object:@"thread2"];

//3.设置队列属性
//1)设置并发数量
queue.maxConcurrentOperationCount = 1;

//2)暂停线程
queue.suspended = YES;

//3)设置线程优先级,需要先暂停线程才会生效
op1.queuePriority = NSOperationQueuePriorityHigh;
op2.queuePriority = NSOperationQueuePriorityVeryLow;

//4.任务完成时调用block
op1.completionBlock = ^{
NSLog(@"op1已经完成");
};

//5.创建任务的另一种方法:block方式
[queue addOperationWithBlock:^{
//也是一个线程入口,和op1、op2一样是一个线程
for (int k=0; k<10; k++) {
NSLog(@"blockThread: %d", k);
}
}];

[queue addOperation:op2];
[queue addOperation:op1];

//6.开始线程
queue.suspended = NO;

for (int k=0; k<10; k++) {
NSLog(@"main: %i", k);
}

}

-(void) thread1:(NSString *) threadName {
for (int i=0; i<10; i++) {
NSLog(@"%@: %d", threadName, i);
}
}

-(void) thread2:(NSString *) threadName {
for (int j=0; j<10; j++) {
NSLog(@"%@: %d", threadName, j);
}
}


③GCD

传送门:http://blog.csdn.net/u012526801/article/details/49004871

补充1:线程中的内存管理问题,NSRunloop和如何跳出线程

NSRunloop:

①线程的生命周期存在5个状态:新建、就绪、运行、阻塞、死亡

②NSRunLoop可以保持一个线程一直为活动状态,不会马上销毁掉

③应用举例:多线程中使用定时器时,必须使用Runloop。因为只有开启Runloop保持线程为活动状态,定时器才不会失效

跳出线程方法:

调用cancel方法,然后再线程方法中根据线程的isCancelled属性可以break出线程方法

①跳出单个线程:[thread1 cancel];

②队列中,跳出多个线程:[queue cancelAllOperations];

内存问题:

多线程创建的实例对象不会放入自动释放池,可能会导致内存泄露。需要手动放入自动重生池

举例:创建一个线程队列queue和一个线程类MyOperation,在queue中添加2个继承于MyOperation类的任务,实现以上补充内容中提到的知识点

以下是viewController中的代码:

- (void)viewDidLoad {
[super viewDidLoad];

_queue = [[NSOperationQueue alloc] init];
_op1 = [[MyOperation alloc] initwithName:@"thread1"];
_op2 = [[MyOperation alloc] initwithName:@"thread2"];

[_queue addOperation:_op1];
[_queue addOperation:_op2];

_op1.completionBlock = ^ {
NSLog(@"op1已经完成------------------");
};

_op2.completionBlock = ^ {
NSLog(@"op2已经完成------------------");
};

//    [self performSelector:@selector(afterDelay) withObject:nil afterDelay:0.1];
[self performSelector:@selector(cancelAllThread) withObject:nil afterDelay:0.5];
}

-(void) afterDelay {
[_op1 cancel];
}

-(void) cancelAllThread {
[_queue cancelAllOperations];
}


以下是MyOperation类的具体实现:

#import <Foundation/Foundation.h>

@interface MyOperation : NSOperation
@property (nonatomic, copy) NSString *mask;

-(instancetype) initwithName:(NSString *)mask;
@end

//##############################################################

#import "MyOperation.h"

@implementation MyOperation

-(instancetype) initwithName:(NSString *)mask {
if (self == [super init]) {
_mask = mask;
}
return self;
}

-(void) main {
//1.多线程创建的实例对象不会放入自动释放池,可能会导致内存泄露。需要手动放入自动重生池
@autoreleasepool {

[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction) userInfo:nil repeats:YES];
//2.开启Runloop来保持线程的存活状态
[[NSRunLoop currentRunLoop] run];

for (int i=0; i<1000; i++) {
//3.cancel方法只是改变isCancelled属性,在线程实现方法中做判断,用于跳出线程方法。
if (self.isCancelled) {
break;
}
NSLog(@"%@: %d", self.mask, i);
}
}
}
-(void) timeAction {
}
@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios 多线程