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
  • 下载

多线程 - 13.RunLoop应用场景

1.定时器场景 通过timer开头的类方法创建定时器时,必须将NSTimer添加到RunLoop中, 才能执行定时器 将NSTimer添加到主线程NSRunLoop的默认模式下, 只有主线程NSRu...

Java---13---多线程---synchronized 同步代码块

还是之前卖票的例子: class Test implements Runnable { private int num = 50; Object obj = new Object()...

黑马程序员_day13_多线程1

----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------ 进程:正在进行中的程序。  线程:就是进程中一个执行单元或执行情...

黑马程序员_java编程基础13 多线程

------- android培训、java培训、期待与您交流! ---------- 1、线程间通讯: 其实就是多个线程在操作用一个资源。但是操作的动作不同。 2、boolean ...

JAVA学习(13) JAVA/C++互相调用 以及多线程

#include #ifdef __cplusplus extern "C" { #endif /* * Class: com_ui_test_test * Metho...

13.浅析COM多线程

ATL一节已经接触过多线程一词,COM为了解决多线程问题的思路如下: 1.支持传统多线程访问,组件编写时处理多线程访问(MTA) 2.支持隐藏多线程细节,组件编写时无需多线程访问(STA) 前者是为了...

Java多线程/并发13、保持线程间的数据独立: Collections.synchronizedMap应用

现在流行分布式计算,分布式计算就是先分开计算,然后统一汇总。比如这道题目: 。先别跑,小学题很简单的。 解释一下,左边那一砣是计算从1加到n的值(求和),右边是n乘到1的值(阶乘),再把两个值相加...

毕向东Java视频学习笔记【Day11-Day13 多线程】

Java_Day12 多线程01 进程:正在进行中的程序(直译). 线程:就是进程中一个负责程序执行的控制单元(执行路径) 一个进程中可以多执行路径,称之为多线程。 一个进程中至少要有一个...

13(多线程)

多线程 1多线程的两种使用方式 第一种:继承Thread类(不建议使用,因为无法多继承) 第二种:实现Runnable接口(建议使用) 栗子:直接用第二种 写一个类实现Runnable接口,并覆盖其中...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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