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

iOS多线程技术

2015-11-30 12:36 381 查看
进程Process:系统中正在运行的一个应用程序

线程Thread:是程序的一段执行序列,是进程的一部分
任务Task: 线程执行的一段序列(逻辑)

进程线程的关系

1. 进程不执行任务,只有线程才执行任务(逻辑)

2. 活动监视器:线程最小值:1个 —>
进程至少有一个线程
3.
主线程:进程至少有一个线程,该线程叫主线程

多线程
四种创建子线程的方式
1. Pthread (了解; 几乎不使用):
POSIX Thread (Portable Operation System Interface): 可移植的操作系统的接口

1) 基于C语言的接口
2) 多平台
1.创建一个子线程对象

/**第二个参数:
指定线程的一些属性(栈空间)(NULL:使用默认的属性)

第三个参数:指向函数的指针(传参类型:void
*; 返回值类型:void *)

第四个参数:
传给task的参数

*/

char
*data = "hello";

pthread_t
pthread;

int
threadError = pthread_create(&pthread,
NULL,
task, data);

if
(threadError != 0) {

NSLog(@"无法创建子线程");
}

//2.将耗时的操作给子线程做
//<#void *(*)(void *)#>

//void *类型:
函数可以返回任意类型的指针(无类型)
//void:
函数没有返回值
void
* task(void
*data) {

printf("Number: %s", (char
*)data);

//执行耗时操作(子线程)

for
(int
i = 0; i <
20; i++) {

NSLog(@"执行次数:%d",
i);

}

return
0;
}
2. NSThread (理解: 其中的一些术语):
优势:基于OC接口;使用方便
缺点:手动管理线程的生命周期 (提高编程的门槛)
三种方式创建子线程
第一种方式:init方式 (多) —> 创建和启动是分离

第二种方式:detach方式 (多) —>
自动创建/启动
第三种方式:perform方式 (了解:用的较少; iOS9不推荐)
1.
适应场景:
创建线程和启动线程的逻辑分开(灵活性高)

//1.创建NSThread对象(selector指定子线程要执行的方法;
object:传给selector方法的参数)

NSThread
*thread = [[NSThread
alloc]
initWithTarget:self
selector:@selector(downloadTask:)
object:@"传入参数"];

//设置thread对象的名字

thread.name
=
@"子线程";

//2.指定线程对象执行耗时操作

//3.手动启动该线程对象
[thread
start];
2.
适用场景:
简单地在子线程中执行selector方法(无法指定线程的名字)
自动的启动一个子线程,
执行selector方法
[self
performSelectorInBackground:@selector(downloadTask:)
withObject:nil];
3.
适用场景:
简单地在子线程中执行selector方法(创建和启动没有分离)
自动的创建子线程;
并且自动启动该子线程
[NSThread
detachNewThreadSelector:@selector(downloadTask:)
toTarget:self
withObject:nil];

备注:

1. [NSThread currentThread]
—>
{number = 1, name = main}:
一定是在主线程中执行

2.
[NSThread currentThread] —>
{number = 2, name = null}:
一定是在子线程中执行 (只要是number非1,就是在子线程)

3. 明确代码执行的顺序

设定线程的优先级(0.0 ~ 1.0; 值越大,优先级越高)

+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;

添加互斥锁(最常用的一种 ): 提供/保证了每次只有一个线程可以执行代码的有效保护形式。

锁: NSLock (推荐)

加锁的时机:开始卖票之前
解锁的时机:卖完一张之后/全部卖完

#import
"ViewController.h"
@interface
ViewController
()//剩余多少票
@property
(nonatomic,
assign)
int
leftTicketCount;//已经卖出多少
@property
(nonatomic,
assign)
int
soldTicketCount;//锁属性
@property
(nonatomic,
strong)
NSLock
*lock;
@end
@implementation
ViewController

- (void)viewDidLoad {

[super
viewDidLoad];

//设置属性的初始值

self.soldTicketCount
=
0;

self.leftTicketCount =
50;

//NSThread
窗口一

NSThread
*thread = [[NSThread
alloc]initWithTarget:self
selector:@selector(saleTicket)
object:nil];
thread.name =
@"窗口一";

NSThread
*secondThread = [[NSThread
alloc]initWithTarget:self
selector:@selector(saleTicket)
object:nil];
secondThread.name =
@"窗口二";

//对锁初始化

self.lock = [NSLock
new];

//手动启动

[thread start];

[secondThread start];
}
//模拟买票逻辑
- (void)saleTicket {

//一直循环

while
(1) {

//加锁

[self.lock
lock];

if(self.leftTicketCount
>
0) {

//还有票

self.leftTicketCount--;

self.soldTicketCount++;

NSLog(@"线程:%@买票成功;剩余票数:%d;已卖出:%d",[NSThread
currentThread],self.leftTicketCount,self.soldTicketCount);

NSLog(@"===============");

//解锁

[self.lock
unlock];

} else
{

//卖完了

NSLog(@"卖完了额");

//解锁

[self.lock
unlock];

//跳出循环

return;

}
}
}
@end

同步锁 (不推荐: 消耗更多的资源)

while (1) {

@synchronized(self) {

//将saleTicket中while逻辑放到此处

}
}

nonatomic:
非原子 (苹果推荐)
atomic:
原子(消耗资源) —> 对这个属性的set方法加锁, 线程安全
@property (atomic, assign) int leftTicketCount;

3.GCD
GCD (Grand Central Dispatch): 伟大的(NB)中枢调度(多线程)解决方案(Solution)
特点:

基于C语言的底层的接口

不知道任何和线程相关的概念(锁/线程对象) —> 降低开发门槛 (money)

所有子线程执行的任务都放到block中 (自动)

自动利用CPU多核的优势, 执行效率高
自动维护线程池, 自动调度各个线程对象
术语

任务: 执行什么操作(代码逻辑)
队列: 用来存放需要执行的任务
通用步骤:

1. 创建一个空的队列

2. 提交一个/多个任务到队列中
3.
执行队列中的任务
队列的类型:

一: 手动创建队列
串行队列 (Serial Queue): 一个一个顺序的执行
创建一个空的串行队列

dispatch_queue_t queue =
dispatch_queue_create("FirstSerialQueue",
DISPATCH_QUEUE_SERIAL);
并行队列 (Concurrent Queue): 多个任务同时执行
创建一个空的并行队列

dispatch_queue_t queue =
dispatch_queue_create("FirstConcurrentQueue",
DISPATCH_QUEUE_CONCURRENT);
二: 系统默认创建的队列
全局队列: 特殊的并行队列
全局队列
特殊的并行队列

dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0);
主队列 (主线程执行): 特殊的串行队列
获取系统创建的主队列

dispatch_queue_t queue =
dispatch_get_main_queue();
执行任务的方式:
同步执行 (Sync): 不会开启新的线程, 在当前线程中执行任务;
等待一个任务, 再在执行另一个任务
把执行的任务放到队列中

dispatch_sync(queue, ^{

//要执行的任务的逻辑
});
异步执行 (Async): 会开启新的子线程执行任务;
立即返回(不会等待任务执行完毕)
把执行的任务放到队列中

dispatch_async(queue, ^{

//要执行的任务的逻辑
});
队列任务的执行特点: FIFO(First In First Out)
总结常用组合:

并行队列+异步执行 (子线程执行block任务 + 立即返回)

全局队列+异步执行 (子线程执行block任务 + 立即返回)
主队列+异步执行 (主线程执行block任务 + 立即返回)

使用GCD的方式来下载图片(耗时操作: 子线程执行)
选择: 全局队列+异步执行

UIButton + UIImageView

图片的地址 (网址)URL(Uniform Resource Locator)
http:/xx/xxx/ss.png
总结:

1. 介绍下载图片的方式:
NSString -> NSURL -> NSData -> UIImage
从子线程回到主线程的方法
1.使用NSObject方法: performSelectorOnMainThread
2.使用NSObject方法: performSelector:OnThread:[NSThread mainThread]
3.dispatch_async(dispatch_get_main_queue(),
^{
//
回到主线程做的
});
4.[[NSOperationQueue
mainQueue]addOperationWithBlock:^{
//
回到主线程做的
}];

GCD把多个任务(下载图片)打包成一个组Group, 调用group_notify, 可以做其他的事情
全局队列+异步执行

dispatch_queue_t
queue =
dispatch_get_global_queue(0,
0);

//创建group对象

dispatch_group_t
group =
dispatch_group_create();

//将任务提到group中

dispatch_group_async(group, queue, ^{

[NSThread
sleepForTimeInterval:5];

NSLog(@"第一个图片下载完毕%@",
[NSThread
currentThread]);
});
通知group中的任务执行完了(合成图片/回到主线程)

dispatch_group_notify(group, queue, ^{

//三个图片已经全部下载完了(子线程)

NSLog(@"三个图片下载完毕:%@",
[NSThread
currentThread]);

//回到主线程

dispatch_async(dispatch_get_main_queue(), ^{

NSLog(@"回到主线程更新界面");

});
});
GCD一次性任务:
一次性任务在程序的整个生命周期只运行一次且一次(one and only once)
dispatch_once(—, ^block {})

4.NSOperation
队列类型
1.非主队列:NSOperationQueue alloc]init];
2.主队列:[NSOperationQueue mainQueue];
发送任务方式
operation start 同步任务
—> NSInvocationOperation的操作由主线程执行
—>
NSBlockOperation类型的操作对象, 第一个是主线程执行, 剩余的由子线程执行
queue addOperation:operation 异步任务
—> NSInvocationOperation和NSBlockOperation都会启动新的子线程执行

常用类: NSOperation (抽象类)
NSInvocationOperation
创建非主队列

NSOperationQueue *queue = [[NSOperationQueue
alloc]
init];
创建NSInvocationOperation对象

NSInvocationOperation *operation = [[NSInvocationOperation
alloc]
initWithTarget:self
selector:@selector(printPlus)
object:nil]
1.同步执行
[operation start];直接添加到主队列中执行;sync同步执行
2.异步执行
[queue
addOperation:operation];
指定执行的任务(添加的瞬间就异步执行)
可以创建多个operation添加到queue

NSBlockOperation
方式一:
创建对象

NSBlockOperation
*operation = [NSBlockOperation
new];

//添加任务

[operation addExecutionBlock:^{

NSLog(@"下载图片111111%@",
[NSThread
currentThread]);

}];

[operation addExecutionBlock:^{

NSLog(@"下载图片2222%@",
[NSThread
currentThread]);

}];

[operation addExecutionBlock:^{

NSLog(@"下载图片3333%@",
[NSThread
currentThread]);

}];

//执行任务(同步)

//第一个操作由主线程做;
剩余操作由子线程做
[operation
start];
方式二:
//1.创建一个非主队列

NSOperationQueue
*queue = [[NSOperationQueue
alloc]
init];

//2.创建操作对象(方式二)

NSBlockOperation
*operation = [NSBlockOperation
blockOperationWithBlock:^{

NSLog(@"下载图片1111%@",
[NSThread
currentThread]);

}];

NSBlockOperation
*otherOperation = [NSBlockOperation
blockOperationWithBlock:^{

NSLog(@"下载图片2222%@",
[NSThread
currentThread]);

}];

//3.执行操作(添加操作到非主队列)

[queue addOperation:operation];
[queue
addOperation:otherOperation];
指定多少个操作同时执行; 设定任务中的依赖关系
设定同时执行任务的个数(起多少子线程)
queue.maxConcurrentOperationCount =
2;

设定依赖关系
[thirdOperation
addDependency:operation];//operation执行完以后thiread执行
[thirdOperation
addDependency:secondOperation];//secondOperation执行完以后thiread执行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: