一、创建和启动线程简单说明
一个NSThread对象就代表一条线程 创建、启动线程 (1) NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start];
// 线程一启动,就会在线程thread中执行self的run方法
sleepForTimeInterval
休眠
主线程相关用法
+ (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;
其他创建线程的方式 (2)创建线程后自动启动线程 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; (3)隐式创建并启动线程 [self performSelectorInBackground:@selector(run) withObject:nil]; 上述2种创建线程方式的优缺点 优点:简单快捷 缺点:无法对线程进行更详细的设置
二、代码示例
必须在调用的方法中加上自动释放池!来释放掉我们在操作过程中的内存!否则会发生内存泄漏
- (
void
)thread1:(
NSString
*)threadName {
@autoreleasepool { for ( int i= 0 ; i< 50 ; i++) { NSLog ( @" 多线程: name:%@ %d" ,threadName,i); }
//在多线程中如果要循环运行需要添加
[[
NSRunLoop
currentRunLoop
]
run
];
}
}
|
一、简介
NSOperation
NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: (1)先将需要执行的操作封装到一个NSOperation对象中 (2)然后将NSOperation对象添加到NSOperationQueue中 (3)系统会⾃动将NSOperationQueue中的NSOperation取出来 (4)将取出的NSOperation封装的操作放到⼀条新线程中执⾏ 2.NSOperation的子类 NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类 使用NSOperation⼦类的方式有3种: (1)NSInvocationOperation (2)NSBlockOperation (3)自定义子类继承NSOperation,实现内部相应的⽅法 |
NSOperationQueue
NSOperationQueue的作⽤:NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的 如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作到NSOperationQueue中,自动执行操作,自动开启线程
---------------------------------------------------------------------------------------------
1、并发数
(1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3
(2)最大并发数:同一时间最多只能执行的任务的个数。
(3)最⼤大并发数的相关⽅方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。
注意:num的值并不代表线程的个数,仅仅代表线程的ID。
提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。
---------------------------------------------------------------------------------------------
2、队列的取消,暂停和恢复
(1)取消队列的所有操作 - (void)cancelAllOperations; 提⽰:也可以调用NSOperation的- (void)cancel⽅法取消单个操作 (2)暂停和恢复队列 - (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列 - (BOOL)isSuspended; //当前状态
(3)暂停和恢复的适用场合:在tableview界面,开线程下载远程的网络界面,对UI会有影响,使用户体验变差。那么这种情况,就可以设置在用户操作UI(如滚动屏幕)的时候,暂停队列(不是取消队列),停止滚动的时候,恢复队列。
---------------------------------------------------------------------------------------------
3、操作优先级
(1)设置NSOperation在queue中的优先级,可以改变操作的执⾏优先级 - (NSOperationQueuePriority)queuePriority; (2)优先级的取值 NSOperationQueuePriorityVeryLow = -8L, NSOperationQueuePriorityLow = -4L, NSOperationQueuePriorityNormal = 0, NSOperationQueuePriorityHigh = 4, NSOperationQueuePriorityVeryHigh = 8
说明:优先级高的任务,调用的几率会更大。
---------------------------------------------------------------------------------------------
4、操作依赖
(1)NSOperation之间可以设置依赖来保证执行顺序,⽐如一定要让操作A执行完后,才能执行操作B,可以像下面这么写 [operationB addDependency:operationA]; // 操作B依赖于操作 (2)可以在不同queue的NSOperation之间创建依赖关系 注意:不能循环依赖(不能A依赖于B,B又依赖于A)。
---------------------------------------------------------------------------------------------
-------------------------------------------------
回到主线程设置UI-----------------------------------------------
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ // 1.执行一些比较耗时的操作
// 2.回到主线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
}];
|
二、NSOperation
线程创建三种方式
--------------------------------------
NSInvocationOperation方式-----------------------------------
//
一、使用
Operation
的子类创建多线程
//1. 创建队列 NSOperationQueue *queue = [[ NSOperationQueue alloc ] init ]; // 先暂停队列 , 为了让队列里面的线程一起执行 后面开启 [queue setSuspended : YES ]; //2. 创建 NSInvocationOperation 对象,封装操作 NSInvocationOperation *operation1=[[ NSInvocationOperation alloc ] initWithTarget : self selector : @selector (test1) object : @"op1" ]; NSInvocationOperation *operation2=[[ NSInvocationOperation alloc ] initWithTarget : self selector : @selector (test2) object : @"op2" ]; //3. 添加到队列 [queue addOperation :operation1]; [queue addOperation :operation2];
----------------------------------------------------
block方式-------------------------------------------------
//
二、使用
block
方式创建多线程
//
直接添加到队列
,
但是不能使之优先级
,
优先级默认是
NSOperationQueuePriorityNormal
[queue
addOperationWithBlock:^{
@autoreleasepool{
for(inti=0; i<50; i++) {
NSLog(@"op3:i:%d",i);
}
}
}];
----------------------------------------
自定义继承NSOperation子类--------------------------------------
//
三、自定义继承
NSOperation
子类创建多线程
MyOperation
*operation4 = [[
MyOperation
alloc
]
initWithTarget
:
self
selector
:
@selector
(test4)];
// 添加到队列 [queue addOperation :operation4]; // 线程添加完成后 恢复队列
[queue setSuspended:NO];
|
自定义NSOperations的子类
{
id
_target;
SEL _sel; }
- (id)initWithTarget:(id)target selector:(SEL)sel;
-----------------------------------------------------------------------------------------------------------------
- (
id
)initWithTarget:(
id
)target selector:(
SEL
)sel {
self = [ super init ]; if ( self ) { _target = target; //viewCtrl _sel = sel; //thread4 } return self ; } // 新开启的线程,调用的入口方法 - ( void )main { @autoreleasepool { [ _target performSelector : _sel withObject : nil ]; }
}
---------------------------------------------------------------------------------------------
|
必须在调用的方法中加上自动释放池!来释放掉我们在操作过程中的内存!否则会发生内存泄漏
- (void)test1
{ @autoreleasepool{ for (int i=0; i<50; i++) { NSLog(@"op1:i:%d",i); } } } - (void)test2 { @autoreleasepool{ for (int i=0; i<50; i++) { NSLog(@"op2:i:%d",i); } } } - (void)test4 { @autoreleasepool{ for (int i=0; i<50; i++) { NSLog(@"op4:i:%d",i); } }
}
|
一、简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数
2.GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方案 GCD会自动利用更多的CPU内核(比如双核、四核) GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程) 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码 3.提示
(1)GCD存在于libdispatch.dylib这个库中,这个调度库包含了GCD的所有的东西,但任何IOS程序,默认就加载了这个库,在程序运行的过程中会动态的加载这个库,不需要我们手动导入。
(2)GCD是纯C语言的,因此我们在编写GCD相关代码的时候,面对的函数,而不是方法。
(3)GCD中的函数大多数都以dispatch开头。
|
一.
队列和任务
1
> 任务 :需要执行什么操作
*
用block
来封装任务
2
>
队列
:存放任务
说明:全局并发队列的优先级 #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中) #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
//
获取并行全局队列
dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//
获取串行主队列
//注意:往主队列中同步添加任务时,容易引起线程死锁
//主队列异步添加任务时不会开启线程
dispatch_queue_t
mainQueue =
dispatch_get_main_queue
();
//
自定义队列
DISPATCH_QUEUE_SERIAL
串行队列
DISPATCH_QUEUE_CONCURRENT
并行队列
dispatch_queue_t
serialQueue =
dispatch_queue_create
(
"serialQueue"
,
DISPATCH_QUEUE_SERIAL
);
---------------------------------------------------------------------------------------------
二.
执行任务的函数
1
> 同步执行
: 不会开启新线程
dispatch_sync...
2
> 异步执行
: 会开启新线程
dispatch_async...
---------------------------------------------------------------------------------------------
三.常见的组合(掌握)
1> dispatch_async + 全局并发队列 2> dispatch_async + 自己创建的串行队列
---------------------------------------------------------------------------------------------
四.线程间的通信(掌握)
-------------------------------------------------
回到主线程设置UI-----------------------------------------------
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程,执行UI刷新操作 }); });
---------------------------------------------------------------------------------------------
五、线程同步(掌握)
1.实质:为了防止多个线程抢夺同一个资源造成的数据安全问题 2.实现:给代码加一个互斥锁(同步锁) @synchronized(self) { // 被锁住的代码
}
注意:锁定1份代码只用1把锁,用多把锁是无效的
---------------------------------------------------------------------------------------------
六、GCD加锁 同步锁
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instace = [[self alloc] init];
});
|
七.延迟执行(掌握)
1> perform.... // 3秒后自动回到当前线程调用self的download:方法,并且传递参数:@"http://555.jpg" [self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3]; 2> dispatch_after... // 任务放到哪个队列中执行 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); double delay = 3; // 延迟多少秒 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{ // 3秒后需要执行的任务 });
八.一次性代码(掌握)
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 这里面的代码,在程序运行过程中,永远只会执行1次 }); |