多线程

一个任务通常就是一个程序,每个运行中的程序通常就是一个进程。也就是说所有运行中的任务通常对应一个进程。我们通常会感觉到cpu会同时执行多个任务,但是事实上每一时刻cpu只能执行一个任务。cpu通过时间片轮转等调度算法,快速地在各个进程之间进行切换,以至于在我们看来能同时并发执行多个任务。

线程NSThread是一个轻量级的进程,线程是进程的组成部分,一个进程可以拥有多个线程,线程在程序中是独立的、并发的执行流。当一个进程被初始化的时候,就会创建一个主线程。线程是独立的,是抢占式的,它在执行的时候并不知道其他线程的存在。总结来说:操作系统可以执行多个任务,每个任务都是一个进程,每个进程可以执行多个任务,每个任务都是一条线程。

我们把一些耗时的操作用多线程的方式操作,开一个子线程来完成这些耗时操作,以避免因为耗时而阻塞主线程。增强用户体验。线程能共享内存,这是进程不能的

iOS中提供了三种多线程编程技术抽象程度由低到高分别是:

1>NSThread

2>CGD

3>NSOperation

NSThread简便但是使用比NSOperation复杂,需要对他进行管理(不常用)(底层oc写的)。NSThread需要管理线程的安全、生命周期。

CGD性能最好(常用)(底层C写的),它能充分利用cpu的多核。

NSOperation更加面向对象,更加方便理解。NSOperation是一个抽象类,我们通常不直接使用它,而是使用它的子类(常用)(底层oc写的)

创建NSThread的两种方法:

1、(id)initWithTarget:selector:object://用这种方法创建需要调用start才会启动线程。

2、-(void)detachNewThreadSelector:toTarget:withObject://用着中方法创建线程不用调用start方法,它创建并启动。

【NSThread currentThread】//获取当前的线程

setName设置线程的名字

当线程创建的时候处于新建状态,当调用start的时候处于就绪状态。


线程终止的三种方式:

1、线程执行完后正常结束

2、线程执行过程中遇到错误异常结束

3、调用NSThread的exit方法退出

NSThread并没有一个方法来终止某个子线程,虽然NSThread提供了cancel方法,但是它只是改变子项成的状态,设置isCancelled的值

如果主线程想要终止某一子线程,课以向子线程发送一个信号,在子线程中判断是否收到这个信号如果收到就调用exit方法。


1、什么时候需要多线程操作?

一般在执行一些耗时操作的时候,需要另外开一条子线程(异步线程)操作
程序运行起来的时候默认有一条线程,主线程。UI,页面跳转,修改UI的一些操作都放在主线程中。

2、进程与线程的区别
一个app运行起来就是一个进程。可以多进程。
进程的三特性:独立性、动态性(进程运行起来之后,UI由主线程决定)、并发性(同时运行多个)
线程:轻量级的进程。多线程环境下,多条线程抢占式执行。

3、线程安全问题
“银行取钱”的问题。


给方法添加过时
加注释/**hhhh*/会在提示框下面显示

线程安全可以加同步锁
NSLOck *_lock = [[NSLock alloc]init]
[_lock lock]
[_lock unlock]

coreFundation是c的框架

@property(automic,asign)int age;
它的底层实现
-(void)setAge:(int)age{
@synchronized(self){
_age = age;
}
}


GCD
同步是按顺序
异步是不按顺序

dispatch_async:异步提交任务,会开启一条子线程无论是同步任务还是异步任务(除了主队列)
dispatch_sync:同步提交任务,不会开子线程,使用当前线程,无论是同步任务还是异步任务

//隐式开启一条子线程
【self performSelectorInBackground:withObject:】
dispatch_queue_t globalQueue =  dispatch_get_global_queue(,对未来的扩展,可以不管,给个小于等于0的数)

[self performSelectorOnMainThread:withObject:waitUntilDone:]

//提交同步任务给主队列(不能这么用,因为它会与主线程相互等待,使得程序不能继续往下执行)

    dispatch_sync(mainQueue, ^{

         NSLog(@"dddd-%@",[NSThread currentThread]);

    });

NSThread可以与CGD连用
线程是不安全的,不能在子线程中对UI进行操作,当修改UI的时候就要回到主线程


//只调用一次
下载图片的时候,防止用户重复点击下载按钮
static dispatch_once_t onceToken;
dispatch_once(& onceToken,^{
//这里面的代码只执行一次
});

队列组
在队列外面再包一层

包含关系
队列组
/*
组(group)
 队列(queue)
任务(task)
组包含队列队列包含任务
*/
队列组只适合异步dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t(3*NSEC_PER_SEC))),
dispatch_get_main_queue(),^{


}
)


NSOperation
1>创建队列
2>创建任务并添加到队列(立马执行)
为线程排序:
通过添加依赖;
NSOperation

//创建队列

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

    //创建任务

    

    //方式1

    /*

    NSBlockOperation *blockOption = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"aaa--%@",[NSThread currentThread]);

    }];

    //将任务添加到队列中

    [operationQueue addOperation:blockOption];//立即执行,会开启一条线程

    */

    

    //方式2

    

    /*

    NSInvocationOperation *invocationOption = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(work) object:nil];

    [operationQueue addOperation:invocationOption];

     */

    /*

    NSBlockOperation *option = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"aaa--%@",[NSThread currentThread]);

    }];

    [option start];//马上执行(它不会开启一个线程,会放入当前线程中执行)不用

   

    */

    //设置在某一段时间并发数量的最大值

    [operationQueue setMaxConcurrentOperationCount:10];

    /*

    //快捷开启子线程

    [operationQueue addOperationWithBlock:^{

        NSLog(@"work-- %@",[NSThread currentThread]);

    }];

     */

    

    /*

    

    //为线程排序使用依赖关系

    //顺序123;依赖关系为3依赖22依赖1

    

    NSBlockOperation *blockOption1 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"aaa--%@",[NSThread currentThread]);

    }];

    NSBlockOperation *blockOption2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"bbb--%@",[NSThread currentThread]);

    }];

    NSBlockOperation *blockOption3 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"ccc--%@",[NSThread currentThread]);

    }];

    

    [blockOption3 addDependency:blockOption2];

    [blockOption2 addDependency:blockOption1];

    

    [operationQueue addOperation:blockOption1];

    [operationQueue addOperation:blockOption3];

    [operationQueue addOperation:blockOption2];

     

     */

    /*

    NSURL *url = [NSURL URLWithString:@""];

    UIImage *img = [[UIImage alloc]initWithData: [NSData dataWithContentsOfURL:url]];

    //返回抓线程刷新UI

    [[NSOperationQueue mainQueue]addOperationWithBlock:^{

        

        NSLog(@"刷新UI");

    }];

     */

    

    

    myOperation *operation = [[myOperation alloc]init];

    //_imgview.image = operation.img;强指针在myOperation改变img的值,在当前controller中也改变

    

    [operation setShouldReturnImg:^(UIImage *img) {

       

        //img刷新UI

        

    }];

    [operationQueue addOperation:operation];

    

    //取消队列中所有任务

    [operationQueue cancelAllOperations];

    

    operationQueue.suspended = YES;//表示暂停

    operationQueue.suspended = NO;//表示恢复

    

    

    

    

}

-(void)work{

    NSLog(@"bbb--%@",[NSThread currentThread]);

    

}


CGD

 初始化两个队列

     

    _srial = dispatch_queue_create("srial", DISPATCH_QUEUE_SERIAL);//串行队列

    _concurrent = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);//串行队列

    

    //提交任务

    dispatch_async(_concurrent, ^{

        //要执行的任务

        NSLog(@"aaa %@",[NSThread currentThread]);

        

    });//提交异步任务

    

    dispatch_sync(_srial, ^{

         NSLog(@"bbb %@",[NSThread currentThread]);

        

    });//提交同步任务

    

    */

    

    

    dispatch_queue_t globleQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0);//第二个参数用于扩展

    //提交异步任务给全局并发队列

    dispatch_async(globleQueue, ^{

        

        NSLog(@"aaa--%@",[NSThread currentThread]);

    

    });//开子线程

    //提交同步任务给全局并发队列

    dispatch_sync(globleQueue, ^{

        NSLog(@"bbb--%@",[NSThread currentThread]);

        

    });//不开子线程

    

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    //提交异步任务给主队列

    dispatch_async(mainQueue, ^{

        NSLog(@"ccc-%@",[NSThread currentThread]);

        

    });//不开子线程

    

    //提交同步任务给主队列(不能这么用,因为它会与主线程相互等待,使得程序不能继续往下执行)

    dispatch_sync(mainQueue, ^{

         NSLog(@"dddd-%@",[NSThread currentThread]);

    });

    

    //队列组

    /*

     网络请求

     1>用户上传头像到服务器(上行)

     2>更新用户信息(下行)

     

     如果开两个子线程,那么久不能保证在更新头像之后,更新数据,如果用同步,那么久会影响到主线程

     解决方法有两个:

     

     

     */

    //解决方法1

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{

        NSLog(@"用户上传头像");

        dispatch_async(dispatch_get_main_queue(), ^{

            

           dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{

               NSLog(@"更新用户信息");

           });

            

        });

        

    });

    

//解决方法2使用队列组

   

/*组包含队列,队列包含任务,队列组使得线程拥有某一顺序完成,但是它还是异步的*/

    

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);

    dispatch_group_async(group, queue, ^{

        //这样就会总是按下面的顺序完成

        dispatch_async(queue, ^{

            NSLog(@"用户上传图片");

        });

        dispatch_async(queue, ^{

           

            NSLog(@"更新用户信息");

        });

        //更新用户信息后会发出通知

        dispatch_group_notify(group, queue, ^{

            NSLog(@"加载完毕");

        });

    });

    

    

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值