iOS开发 - 多线程

知识点

1.理解线程的概念

2.NSThread的使用

3.NSOperation的使用

4.GCD的使用

5.线程锁,线程安全

===============================

1.多线程是一种实现多任务并发执行的技术,允许同时执行多个任务,能够更合理的利用CPU的资源,提高效率、防止用户界面卡顿。

在iOS中,所有的UI处理只能在主线程做。

什么是进程?

· 简单的说进程就是我们电脑上运行的一个个应用程序,每一个程序就是一个进程,并且每个进程之间是独立的,每个进程运行在其专用受保护的内存空间内(window系统可以通过任务管理器进行查看,Mac系统中可以通过活动监视器对其进行查看)

什么是线程?

· 通过上面的介绍我们知道了什么是进程,那么如何让进程运行起来,这个时候就要有线程了,也就是说每个应用程序想要跑起来,最少也要有一条线程存在,其实应用程序启动的时候我们的系统就会默认帮我们的应用程序开启一条线程,这条线程也叫做’主线程’,或者’UI线程’

进程和线程之间的关系

· 线程是进行的执行单元,进程的所有任务都在线程中执行,举例来说:进程就好比公司中的一个个部门,线程则代表着部门中的同事,而主线程当然是我们的老板了,一个公司部能没有老板,一个程序不能没有线程其实都是一个道理.

什么是CPU?

· CPU(中央处理器,Central Processing Unit)是一块超大规模的集成电路,只要用来解释计算机指令以及处理计算机软件中的数据.

多线程的原理

· 同一时间,CPU值能处理一个线程,只有一条线程在执行,多线程指的就是多条线程同时执行,其实就是CPU快速的在多条线程之间的切换,如果CPU调度线程的时间足够快,那么就会造成多线程并发执行的假象,而当线程特别多的时候,那么CPU在多条切换的效率也就会下降,同时消耗大量的CPU资源,线程的执行效率也就会下降.

多线程优点

· 能适当提高程序的执行效率

· 能适当提高资源的利用率

多线程的缺点

· 开启线程需要占用一定的内存空间,如果开启大量的线程,则会占用大量的内存空间,降低程序的性能

· 线程越多,CPU在调度线程上得开销就越大,程序的设计上也就更加的复杂,因此不推荐开启太多的线程,一般开启2~5条为最佳(且用且珍惜);

主线程

· 也就是应用程序启动的时候,系统默认帮我们创建的线程,称之为’主线程’或者是’UI线程’;

· 主线程的作用一般都是用来显示或者刷新UI界面例如:点击,滚动,拖拽等事件

===============================

2.NSThread线程控制

1).创建线程,并自动执行

[NSThread detachNewThreadSelector:@selector(doSomeThing) toTarget:self withObject:nil];

2).创建线程,不自动执行
    [[NSThread alloc] initWithTarget:self selector:@selector(doSomeThing) object:nil];

3).设置线程名
    thread.name = @"另一个线程";

4).执行线程
    [thread start];

5).线程取消
    [thread cancel];

6).函数内获取当前线程
    [NSThread currentThread];

7).获取主线程
    [NSThread mainThread];

7).线程休眠
    [NSThread sleepForTimeInterval:1.0f];  // 休眠几秒
    [NSThread sleepUntilDate:date]; // 休眠到指定时间

8).线程退出
    [NSThread exit];

9).线程通信
    [self performSelector:@selector(function) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];

===============================

3.NSOperation,是以任务为中心的一种多线程技术,并不直接管理线程

1).NSOperation是抽象父类,不要直接使用,而应该使用它的子类

NSInvocationOperation

[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomeThing) object:nil];

    NSBlockOperation
        [NSBlockOperation blockOperationWithBlock:^{}];

    添加任务间的依赖关系,前者依赖于后者的完成,也就是后者执行完,前者才能执行,依赖关系需要放在添加到队列之前设置
        [invocation addDependency:blockOperation];

    如果有必要,可以让Operation取消
         [invocation cancel];

2.NSOperationQueue,任务队列,NSOperation对象需要添加到队列里面才会执行
    添加到队列里之后,自动会给每个NSOperation对象创建一个线程去执行

    创建NSOperationQueue
        [[NSOperationQueue alloc] init];

    设置最大并发数
        queue.maxConcurrentOperationCount = 1;

    添加任务到队列里
        [queue addOperation:blockOperation];

    让队列里面,所有的Operation都取消
        [queue cancelAllOperations];

    获取当前线程对列
        currentQueue

    获取主线程对列
        mainQueue

===============================

4.GCD是一套C语言的线程控制API,是NSOperation的底层实现,用Block来表示一个任务

1).创建队列

dispatch_queue_create(“QF Queue”, DISPATCH_QUEUE_CONCURRENT);

2).系统的队列
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //  全局队列
    dispatch_get_main_queue();    //  主线程队列

3).异步执行任务
    dispatch_async(globalQuque, ^{});

4).创建分组
    dispatch_group_create();

5).添加任务到分组,并执行
    dispatch_group_async(group, globalQuque, ^{});

6).分组执行完的通知
    dispatch_group_notify(group, mainQuque, ^{});

===============================

5.线程锁

1).方式1:

_lock = [[NSLock alloc] init];

[_lock tryLock];
[_lock unlock];

2).方式2:
   @synchronized(self) {}

NSThread

//多线程 -- 为了将一些耗时的操作放在多线程中去执行 主要是为了给一个好的用户体验,防止卡顿的效果
//越多越好? 消耗内存和cpu的使用效率

//创建多线程的方式
//1.NSThread
//2.CGD
//3.NSOperation
//程序运行的时候,会默认创建一个线程,这个线程称之为主线程/UI线程,所有的UI相关的操作都需要在这个线程中执行
BOOL res1 = [NSThread isMainThread]; //判断是否是子线程
BOOL RES2 = [NSThread isMultiThreaded]; //判断是否是多线程

//1.创建线程 减方法创建

//操作 – 功能 – 若干行代码 – 函数 – 任务

NSThread * thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];

//第三个参数: object 如果第二个参数selector带参的话 就使用object传递

//新创建的线程称之为子线程或者任务线程/后台线程

//线程的名字
thread1.name = @"子线程1";
//线程的优先级(double) 0 - 1
thread1.threadPriority = 0.5;
//设置线程的优先级(枚举值)需要在线程开启前设置 否则无效。
thread1.qualityOfService = NSQualityOfServiceBackground;

//2.开启线程
[thread1 start];

//创建线程 加方法创建并且执行线程

[NSThread detachNewThreadSelector:@selector(threadRun) toTarget:self withObject:nil];

//设置不了线程的名字 可以到方法里通过currentThread方法拿到线程 再进行赋值操作

//NSObject方法 创建线程

[self performSelectorInBackground:@selector(threadRun) withObject:nil];

GCD

//GCD - 基于C语言的一套API接口,它是把Block作为任务,添加到队列中进行操作

//GCD 优点:可以控制多个线程的执行顺序 这个功能是NSThread不具有的 

//缺点: 不能取消线程
//GCD 语法都是c语言函数
//1.创建队列
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);

//queue 队列/线程池
//dispatch 调度/执行
//第一个参数 队列的名字 通常写nil
//第二个参数 串行/并行
//DISPATCH_QUEUE_SERIAL 串行  按顺序执行队列里的线程
//DISPATCH_QUEUE_CONCURRENT 并行  同时执行若干个线程

监听线程的退出

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(threadOut) name:NSThreadWillExitNotification object:nil];
//NSThreadWillExitNotification 线程退出的频道
//只需要监听这个频道 当线程退出的时候 就会收到通知/消息 然后调用响应的方法

//取消线程 cancel并不能把一个线程退出 调用cancle方法只是为了告诉当前线程的isCancelled属性为YES 并且触发监听
[thread cancel];

if (thread.isCancelled) {
    //如果为YES 退出线程 也可以使用return
    [NSThread exit];
}
//threadRun这个方法是我们子线程的入口函数 - 当这个方法执行完毕的时候,线程就已经是死亡状态了

定时器

//GCD定时器
//1.创建定时器
//需要把定时器定义成全局变量 否则会被立刻释放
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
//2.设置定时器 第一个参数为时间间隔 第二个参数次数
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//3.定时器定时的操作
dispatch_source_set_event_handler(self.timer, ^{
    //定时器每隔几秒钟要做的操作
    NSLog(@"d");
});
//执行定时器
dispatch_resume(self.timer);

延时操作

[NSThread sleepForTimeInterval:2.0];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];

-(void)createQueue2{
    NSLog(@"将要延时...");
    //延时几秒操作
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //DISPATCH_TIME_NOW 从现在开始
        //NSEC_PER_SEC 代表的是秒
        //延时几秒之后的操作
        NSLog(@"延时执行");
    });
    [self performSelector:@selector(afterRun) withObject:nil afterDelay:2.0];
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
}

线程组

//线程组  监听线程
dispatch_group_t group = dispatch_group_create();
//创建全局队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

dispatch_group_async(group, queue, ^{

    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"线程1执行完毕");
});

dispatch_group_async(group, queue, ^{

    [NSThread sleepForTimeInterval:3.0];
    NSLog(@"线程2执行完毕");
});
//前两个线程结束后会通知这个线程
dispatch_group_notify(group, dispatch_get_main_queue(), ^{

    NSLog(@"返回主线程");
});

阻塞线程组

dispatch_group_t group = dispatch_group_create();
//异步操作组
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{

    for (int i = 0; i < 5; i ++) {
        //进入线程组
        dispatch_group_enter(group);
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"线程 --- %d",i);
        //离开线程组
        dispatch_group_leave(group);
    }
});
//目的:先执行完前面的线程 再执行后面的线程
//阻塞线程组
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
//异步操作队列
dispatch_async(dispatch_get_global_queue(0, 0), ^{

    NSLog(@"另一个线程执行了");
});

pragma mark - 重复

-(void)createQueue1{

//重复执行某个线程

//第一个参数 重复执行的次数

dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t idx) {

NSLog(@”线程执行…”);

});

}

pragma mark - 栅栏

-(void)createQueue2{

dispatch_queue_t queue = dispatch_get_global_queue(0,0);

dispatch_async(queue, ^{
    NSLog(@"线程1");
});

dispatch_async(queue, ^{
    NSLog(@"线程2");
});
dispatch_barrier_async(queue, ^{
    NSLog(@"barrier...");
});
dispatch_async(queue, ^{
    NSLog(@"线程3");
});

}

pragma mark - 信号量

-(void)createQueue3{

//信号量
//创建信号量 参数为计数
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    //等待接收信号 接收信号要写在当前线程所有操作之前 计数-1
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"线程1执行...");
});

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"线程2执行...");
    //发送信号 在当前线程操作执行完毕之后 再发送信号  计数+1
    dispatch_semaphore_signal(semaphore);
});

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"线程3执行...");
});

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"线程4执行...");
});

}

时间: 2024-12-06 07:15:10

iOS开发 - 多线程的相关文章

iOS开发多线程篇—线程的状态

iOS开发多线程篇—线程的状态 一.简单介绍 线程的创建: self.thread=[[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil]; 说明:创建线程有多种方式,这里不做过多的介绍. 线程的开启: [self.thread start]; 线程的运行和阻塞: (1)设置线程阻塞1,阻塞2秒 [NSThread sleepForTimeInterval:2.0]; (2)第二种设置线程阻塞2,以当前时

iOS开发多线程之自定义NSOperation

iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UITableViewController. 1 // 2 // YYViewController.h 3 // 01-自定义Operation 4 // 5 // Created by apple on 14-6-26. 6 // Copyright (c) 2014年 itcase. All rig

iOS开发多线程篇—自定义NSOperation

iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UITableViewController. 1 // 2 // YYViewController.h 3 // 01-自定义Operation 4 // 5 // Created by apple on 14-6-26. 6 // Copyright (c) 2014年 itcase. All rig

iOS开发多线程篇 09 —NSOperation简单介绍

iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作?:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: (1)先将需要执行的操作封装到一个NSOperation对象中 (2)然后将NSOperation对象添加到NSOperationQueue中 (3)系统会?动将NSOperationQueue中的NSOpe

iOS开发多线程篇 05 —GCD介绍

iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方案 GCD会自动利用更多的CPU内核(比如双核.四核) GCD会自动管理线程的生命周期(创建线程.调度任务.销毁线程) 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码 3.提示 (1)GCD存在于libdispatch.dylib这个库中

iOS开发多线程篇—多线程简单介绍

iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcode,系统就会分别启动2个进程 通过“活动监视器”可以查看Mac系统中所开启的进程 2.什么是线程 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行 比如使用酷狗播放音乐.使用迅雷下载电影,都需要在线程中执行 3.线程

iOS开发多线程篇—多线程的的相关概念(1)

iOS开发多线程篇-多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcode,系统就会分别启动2个进程 通过"活动监视器"可以查看Mac系统中所开启的进程 2.什么是线程 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行 比如使用酷狗播放音乐.使用迅雷下载电影,都需要在线程中执行

IOS开发——多线程编程

1."省电,流畅,优质应用,响应速度快,用户体验好--"也许是众多用户眼中的苹果系统. 2.在众手机商拼CPU主频,拼4核,8核的年代,苹果依然坚持双核,iphone用户体验仍然坚挺. 以上两点IOS是如何优化,在续航,流畅度和响应速度上完胜安卓,答案就是多线程&RunLoop... RunLoop是IOS事件响应与任务处理最核心机制,它贯穿IOS整个系统运作. RunLoop不像一般的线程循环等待任务,传统的线程循环等待任务会导致CPU时间被占用,虽然你设置了睡眠时间,但很多

iOS开发多线程篇—GCD的基本使用

iOS开发多线程篇—GCD的基本使用 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进行处理,那么不论处理函数是异步的还是同步的都不会开启新的线程. 获取主队列的方式: dispatch_queue_t queue=dispatch_get_main_queue(); (1)使用异步函数执行主队列中得任务,代码示例: 1 // 2 // YYViewController.m 3 //

iOS开发多线程篇 10 —NSOperation基本操作

iOS开发多线程篇—NSOperation基本操作 一.并发数 (1)并发数:同时执?行的任务数.比如,同时开3个线程执行3个任务,并发数就是3 (2)最大并发数:同一时间最多只能执行的任务的个数. (3)最?大并发数的相关?方法 - (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt; 说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能