13-多线程

原创 2015年07月08日 19:01:32

1.NSThread
一、创建和启动线程简单说明

一个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种创建线程方式的优缺点

优点:简单快捷

缺点:无法对线程进行更详细的设置


二、代码示例
NSThread  *thread=[[NSThread alloc]initWithTarget:self selector:@selector(thread1)object:@"线程A"]; 
//为线程设置一个名称
thread.name=@"线程A"; 
//开启线程    
[thread start];
----------------------------------------------回到主线程设置UI---------------------------------------------
//回到主线程执行方法
[self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
必须在调用的方法中加上自动释放池!来释放掉我们在操作过程中的内存!否则会发生内存泄漏
- (void)thread1:(NSString*)threadName {

   
@autoreleasepool{
       
       
       
for (int i=0; i<50; i++) {
           
NSLog(@"多线程:name:%@  %d",threadName,i);
        }
       
        //在多线程中如果要循环运行需要添加[[NSRunLoopcurrentRunLoop]run];

    }

}



2.NSOperation
一、简介

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;
- (void)setQueuePriority:(NSOperationQueuePriority)p;

 (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 = [[NSOperationQueuealloc]init];
   
//先暂停队列,为了让队列里面的线程一起执行后面开启
    [queue
setSuspended:YES];
   
   
//2.创建NSInvocationOperation对象,封装操作
   
NSInvocationOperation*operation1=[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(test1)object:@"op1"];
   
   
NSInvocationOperation*operation2=[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(test2)object:@"op2"];

   
//3.添加到队列
    [queue
addOperation:operation1];
    [queue
addOperation:operation2];
   
----------------------------------------------------block方式-------------------------------------------------   
//二、使用block方式创建多线程
    //直接添加到队列,但是不能使之优先级,优先级默认是NSOperationQueuePriorityNormal
    [queueaddOperationWithBlock:^{
       @autoreleasepool{  
       for(inti=0; i<50; i++) {
           NSLog(@"op3:i:%d",i);
        }
       }
    }];


----------------------------------------自定义继承NSOperation子类--------------------------------------    
//三、自定义继承NSOperation子类创建多线程
    MyOperation *operation4 = [[MyOperationalloc]initWithTarget:selfselector:@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{
       
        [
_targetperformSelector:_selwithObject: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);
        }
    }
}


3.GCD

一、简单介绍

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_tmainQueue = dispatch_get_main_queue();
   
//自定义队列DISPATCH_QUEUE_SERIAL串行队列DISPATCH_QUEUE_CONCURRENT并行队列
dispatch_queue_tserialQueue = 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秒后自动回到当前线程调用selfdownload:方法,并且传递参数:@"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

});


版权声明:本文为博主原创文章,未经博主允许不得转载。

13.尚硅谷_java基础_多线程

  • 2013年09月26日 14:50
  • 1.58MB
  • 下载

android学习笔记(13) intent Services多线程初步

IntentService是Service类的子类,用来处理异步请求,客户端通过startService(intent)方法传递请求给IntentService,IntentService通过worh...
  • sac761
  • sac761
  • 2015年09月03日 19:12
  • 845

Java多线程 -- JUC包源码分析13 -- Callable/FutureTask源码分析

关于Runnable,我们都已经很熟悉了。在上一篇,我们也分析了ThreadPoolExecutor用来执行任务的接口execute,如下所示:public interface Runnable { ...

多线程,它是让计算机更好用的东西,也是程序员最容易犯错的东西----小话c语言(13)

[Mac-10.7.1  Lion  Intel-based  x64  gcc4.2.1] Q:  c标准中包含线程操作么? A: 没有。 Q: 给个mac下线程操作的例子吧。...

VC++深入详解(13):详细分析控制台应用程序下的多线程输出

最近写了了个问题很多的多线程程序,在里面我没有使用互斥对象,用它来探索多线程程序到底是如何运行的,在众多网友的帮助下,得到了很多有意义的结果,现整理如下。(如果有错误的观点,敬请批判)首先说明,我的笔...

13、Notification与多线程

前几天与同事讨论到Notification在多线程下的转发问题,所以就此整理一下。 先来看看官方的文档,是这样写的: In a multithreaded application, notific...
  • zwcshy
  • zwcshy
  • 2015年03月31日 21:14
  • 293

《高效编程十八式》(8/13)多线程

多线程 王伟冰     什么是多线程?多线程有什么用?先来看一个例子。     假设我们要写一个播放在线视频的程序,那么肯定会有两个步骤:下载视频,然后再播放视频。简单用代码表示就是这样: ...

4-13-指针、劫持、递归、多线程

1、指针 int num = 10; printf("%p", &num);//可以通过两种方式(直接、间接)修改num值,间接赋值有两种方式(直接内存修改、使用指针进行修...
  • grepme
  • grepme
  • 2016年10月16日 18:28
  • 180

Chp13 多线程

此文的内容包括:     ·多线程与并发的概念     ·Thread类和Runnable接口     ·线程的状态     ·线程同步     ·synchronized与同步代码块     ·...

13.高级IO和多线程和线程同步

13.1.阻塞式和非阻塞式IO 13.2.进程和线程的对比 13.3.线程同步之信号量+互斥锁+条件变量...
  • Rston
  • Rston
  • 2016年10月21日 22:28
  • 861
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:13-多线程
举报原因:
原因补充:

(最多只允许输入30个字)