iOS基础之多线程

作者: 平安喜乐698 | 来源:发表于2019-07-10 12:08 被阅读0次
    目录
        1. 概念
        2. 使用(4种方式)
    
    1.概念 (程序、进程、线程、多线程)

    程序

    一个应用就是一个程序,用于完成某种功能。
    启动一个应用程序后,会创建一个进程,该进程会创建一个主线程。
    

    进程

    1、简介
     (1)一个进程是指在系统中正在运行的一个应用程序。
     (2)进程间相互独立,每个进程均运行在其专用且受保护的内容空间内。
     (3)通过“活动监视器”可以查看mac系统中所开启的进程。
    
    2、进程通信
     单机系统中进程通信有四种形式:主从式、会话式、消息或邮箱机制、共享存储区方式。
        主从式例子:终端控制进程和终端进程。
        会话式例子:用户进程与磁盘管理进程之间的通信。
    

    线程

    简介
    
    (1)线程(Thread),也称作轻量级进程。线程是进程的组成部分,一个进程可以拥有多个线程(至少有一个主线程)。
    (2)线程在程序中是独立的、并发的执行流,当进程被初始化后,主线程就被创建了。
    (3)可以在进程内创建多条顺序执行流,这些顺序执行流就是线程,每条线程是相互独立的。
    (4)线程是独立运行的,单个线程他是不知道进程中是否存在其他的线程,线程的执行是抢占式的。(当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行)。
    (5)3个基本状态:就绪,执行,阻塞
    (6)一个进程要想执行任务,必须得有线程(每一个进程至少要有一条线程,可以有多个线程)。
    (7)线程是进程的基本执行的单元,一个进程(程序)的所有的任务都在线程中执行。
    (8)一个线程中的任务的执行是串行的。(如果要在一个线程中执行多个任务,那么只能一个一个地按照顺序执行这些任务)。
    (9)在同一时间内,一个线程只能执行一个任务。
    
    线程的生命周期是:新建 - 就绪 - 运行 - 阻塞 - 死亡
    

    多线程

    1、简介
     (1)一个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务。
     (2)多线程技术可以提高程序的执行效率。
     
    2、原理(单核)
     (1)同一时间,CPU只能处理一条线程,只有一条线程在工作(执行)。
     (2)多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)。
     (3)如果CPU调度线程的时间足够快,就会造成了多个线程并发执行的假象。
     (4)如果线程非常多,CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源,每条线程被调用执行的频次会降低(线程的执行效率降低)。
     
    3、优缺点
    优点:
        适当提高程序的执行效率、资源利用率(CPU、内存利用率)。
     (1)对于单线程的应用而言,整个应用只有一个顺序执行流,当执行流在某个耗时操作或不能立即完成的任务时(如网络请求、复杂的操作和运行过程、某些必须消耗一定时间后才能完成的操作),该执行流就会被阻塞,整个应用就会被卡在那里无法继续执行,因此单线程的程序往往功能非常有限。
     (2)在实际应用中多线程是非常有用的,例如:用户操作界面上的某个按钮时,该按钮需要执行的任务需要几秒甚至十几秒,如果直接在UI线程(主线程)中完成这个任务,在该任务执行完成、返回之间,UI线程被该任务阻塞,无法响应用户的其他操作(这段时间内,用户对iOS系统的操作将不会有任何反应,除非用户单机Home键返回,但这并不是用户希望的结果)。
    缺点:
     (1)开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能。
     (2)线程越多,CPU在调度线程上的开销就越大。
     (3)程序设计更加复杂:如线程之间的通信,多线程的数据共享。
     
    4、在iOS开发中的应用
        一个iOS程序运行后,默认会开启1条线程,称为主线程(UI线程)。
        主线程用来
            1、显示、刷新UI界面
            2、处理UI事件(点击事件、滚动事件、拖曳事件等)。
        比较耗时的操作不要放在主线程中。耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种卡的坏的体验。
    
    多线程资源共享带来的安全隐患
            一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源。当多个线程访问同一资源时,很容易引发数据散乱和数据安全问题。(如多个线程访问同一个对象、同一个变量、同一个文件)。
    
    解决方法:使用互斥锁
            使用的格式:@synchronized(锁对象){//需要锁定的代码}     注:锁定一份代码只用一把锁,用多吧锁是无效的。
        互斥锁的优点
            能有效防止因多线程抢夺资源造成的数据安全问题
        互斥锁的缺点
            需要消耗大量的CPU资源。
        互斥锁的使用前提
            多条线程抢夺同一块资源。(互斥锁就是使用了线程同步技术,多条线程按顺序地执行任务)。
    
    示例:在创建单例模式时,最好使用互斥锁。
     static UserInfo *singletonUserInfo = nil;
     +(UserInfo *)shareUserInfo{
     @synchronized(self){
     //创建一个线程锁,防止多线程中多次创建
     if (singletonUserInfo == nil) {
     singletonUserInfo = [[UserInfo alloc]init];
     NSLog(@"初始化");
     }
     }
     return singletonUserInfo;
     }
    
    
    atomic
        原子性,为setter方法加锁(默认就是atomic),线程安全,需要消耗大量的资源
    nonatomic
        非原子性,不会为setter方法加锁,非线程安全,适合内存小的移动设备
     iOS开发:最好所有属性都声明为nonatomic,尽量避免多线程抢夺同一块资源,尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力。
    

    简单总结

     1.一个程序至少有一个进程,一个进程至少有一个线程。
        进程创建则主线程创建,主线程死掉则进程死掉。
     2.进程是最小的资源分配单位,线程是最小的CPU执行单位。
        进程之间相互独立,且所有任务都交由线程去执行。
        多个线程之间相互独立,但共享同一进程的资源。
     3.更新UI要放在主线程中(否则:防止造成卡顿,避免多个子线程同时操作UI)
    

    同步/异步/串行/并行

     同步:任务块完成后再继续向下执行
     异步:跳过任务块继续向下执行
     串行:是指一个队列,队列中的任务依次执行
     并行:是指一个队列,队列中的任务同时执行
     
    4种(首先先考虑队列,再考虑同异步)
       同步串行(在串行队列中,造成死锁)
       同步并行
       异步串行
       异步并行
    
    2. 使用(4种方式)
    1. pthread
    基于C语言
    
    #import <pthread.h>
    
        // 1. 创建线程
        pthread_t thread;
        // 2. 开启线程(线程,线程属性,函数,函数参数)
        pthread_create(&thread, NULL, run, NULL);
        // 3. 设置该线程运行结束后自动释放所有资源
        pthread_detach(thread);
    
    // 线程操作方法(放在OC方法外)
    void *run(void *param){
        for(int i=0;i<1000;i++){
            
        NSLog(@"%d=====%@",i, [NSThread currentThread]);
        }
        return NULL;
    }
    
        pthread_cancel(thread); // 中断指定线程
        pthread_exit(thread);   // 终止指定线程
    
        // 待改
        pthread_join()  阻塞当前的线程,直到另外一个线程运行结束
        pthread_attr_init() 初始化线程的属性
        pthread_attr_setdetachstate() 设置脱离状态的属性(决定这个线程在终止时是否可以被结合)
        pthread_attr_getdetachstate() 获取脱离状态的属性
        pthread_attr_destroy() 删除线程的属性
        pthread_kill() 向线程发送一个信号
    
    1. NSThread
    创建线程
    (方式一)(创建后调用start启动)
        NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(method:) object:@""];
    (方式二)(创建后调用start启动)
        NSThread *thread1=[[NSThread alloc]initWithBlock:^{
        }];
    (方式三)(创建后自动启动)
        [NSThread detachNewThreadSelector:@selector(method:) toTarget:self withObject:@""];
    (方式四)(创建后自动启动)
        [NSThread detachNewThreadWithBlock:^{
        }];
    (方式五)(隐式创建)
        //
        [self performSelector:@selector(method)];
        [self performSelector:@selector(method) withObject:nil];
        [self performSelector:@selector(method) withObject:nil withObject:nil];
        [self performSelector:@selector(method) withObject:nil afterDelay:1.0];
        [self performSelector:@selector(method) withObject:nil afterDelay:1.0 inModes:@[NSRunLoopCommonModes]];
        //
        [self performSelector:@selector(method) onThread:thread withObject:nil waitUntilDone:true];
        [self performSelector:@selector(method) onThread:thread withObject:nil waitUntilDone:true modes:@[NSRunLoopCommonModes]];
        // 
        [self performSelectorInBackground:@selector(method) withObject:nil];
        // 主线程
        [self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:true];
        [self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:true modes:@[NSRunLoopCommonModes]];
    
    thread实例方法
    
        // 是否是主线程
        BOOL isMain=[thread isMainThread];
        // 是否正在执行
        BOOL isExecuting=[thread isExecuting];
        // 是否已结束
        BOOL isFinished=[thread isFinished];
        // 是否被取消
        BOOL isCanceled=[thread isCancelled];
    
        // 获取线程名
        NSString *threadName=thread.name;
        // 设置线程名
        [thread setName:@"name"];
    
        // start
        [thread start];
        // cancel
        [thread cancel];
    
        // 获取所占的栈区大小
        NSUInteger *size=[thread stackSize];
        // 设置所占的栈区大小
        [thread setStackSize:1024*5];
    
        // 获取优先级
        double x=thread.threadPriority;
        // 设置优先级
        [thread setThreadPriority:1000];
    
    NSThread类方法
        // 获取主线程
        NSThread *mainThread=[NSThread mainThread];
    
    
    当前线程相关
        // 获取当前线程
        NSThread *currentThread=[NSThread currentThread];
        // 杀死当前线程
        [NSThread exit];
    
        // 阻塞当前线程10s
        [NSThread sleepForTimeInterval:10];
        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    
        // 判断当前线程是否多线程
        BOOL isMutiThread=[NSThread isMultiThreaded];
        // 判断当前线程是否是主线程
        BOOL isMainThread=[NSThread isMainThread];
    
        // 获取/设置当前线程的调度优先级
        // 调度优先级的取值范围是0.0~1.0,默认0.5,值越大,优先级越高。
        double priority=[NSThread threadPriority];
        // 设置调度优先级
        [NSThread setThreadPriority:0.5];
    
    通知
    
        // 即将进入多线程模式
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(willBecomeMuti:) name:NSWillBecomeMultiThreadedNotification object:nil];
        // 进入单线程模式
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(becomeSigle:) name:NSDidBecomeSingleThreadedNotification object:nil];
        // 线程退出
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(willExit:) name:NSThreadWillExitNotification object:nil];
    
    1. GCD
    自动管理线程的生命周期(创建线程,调度任务,销毁线程等)
    
    同步/异步
    主线程队列/全局线程队列/自定义线程队列
        // 同步  1.主线程队列(串行)
        dispatch_sync(dispatch_get_main_queue(), ^{
        });
        // 异步  2.全局线程队列(并行)
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            // 耗时操作
            // 。。。
            dispatch_async(dispatch_get_main_queue(), ^{
                // UI操作
                // 。。。 
            });
        });
    3.自定义线程队列    
        // 串行
        dispatch_queue_t queue=dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
        // 并行
        dispatch_queue_t queue2=dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
    
    
    延迟
        // 延迟2s执行
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*2), dispatch_get_main_queue(), ^{
        });
        
    
    重复
        // 重复3次执行
        dispatch_apply(3, dispatch_get_main_queue(), ^(size_t x) {
        });
        
    
    onlyOne    
        // 仅执行一次
        static dispatch_once_t predicate;
        dispatch_once(&predicate, ^{
            //
        });
    
    
    栅栏(任务先后)
        // dispatch_barrier_async先执行栅栏之前任务,再执行栅栏任务,再执行栅栏后的任务
        dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-1");
        });
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-2");
        });
        dispatch_barrier_async(concurrentQueue, ^(){
            NSLog(@"dispatch-barrier");
        });
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-3");
        });
        dispatch_async(concurrentQueue, ^(){
            NSLog(@"dispatch-4");
        });
    
    组 (任务先后)   dispatch_group_t
    
    // 
        dispatch_queue_t dispatchQueue = dispatch_queue_create("ted.queue.next", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_t group=dispatch_group_create();
        dispatch_group_async(group, dispatchQueue, ^{
        });
        dispatch_group_async(group, dispatchQueue, ^{
        });
        // group内所有队列完成后调用
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        });
    
    
    // 设置最大并行数    
        // 创建队列组
        dispatch_group_t group = dispatch_group_create();
        // 创建信号量,并且设置值为3
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        for (int i = 0; i < 100; i++){
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            dispatch_group_async(group, queue, ^{
                NSLog(@"%i",i);
                sleep(2);
                // 每次发送信号则semaphore会+1,
                dispatch_semaphore_signal(semaphore);
            });
        }
    /*
    同步锁
        // dispatch_semaphore_t 信号量:用于同步
        // 1.创建信号量(个数>=0)  (放在代码块上)
        dispatch_semaphore_t semaphore=dispatch_semaphore_create(0);
        // 2.信号量个数+1          (放在代码块中)
        dispatch_semaphore_signal(semaphore);
        // 3. 等待直到信号量个数>0   (放在代码块下)
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        // 3. 10s内等待直到信号量个数>0
        dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 10));
    */
        
    同步锁2
        dispatch_group_t group=dispatch_group_create();
        // 进入组
        dispatch_group_enter(group);
        dispatch_group_async(group, dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT), ^{
            // 离开组
            dispatch_group_leave(group);
        });
    /*
    成对
        // 进入组
        dispatch_group_enter(group);
        dispatch_group_async(group, dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT), ^{
            // 离开组
            dispatch_group_leave(group);
        });
    */
        // 等待直到离开组
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    1. NSOperation
    NSOperation是对GCD的封装。
    相比GCD
        优点:比GCD更强大(能处理大量的并发请求,更好的处理队列之间的依赖关系)
        缺点:比GCD效率低.
    
    
    自动管理线程的生命周期(创建线程,调度任务,销毁线程等)
    
        // 1.创建queue队列
        NSOperationQueue *optionQueue=[NSOperationQueue new];
        // 主队列(串行,最大并行数:1)
        // NSOperationQueue *que=[NSOperationQueue mainQueue];
        // 1.1设置queue最大并行数(为1则串行,默认:-1并行)
        [optionQueue setMaxConcurrentOperationCount:5];
        
        // 将option加入queue,会自动执行,不用option start
        // 2.添加blockOption到queue
        //  : NSOperation
        // 创建option 
        NSBlockOperation *option=[NSBlockOperation blockOperationWithBlock:^{
        }];
        // 设置option代码块完成时调用
        [option setCompletionBlock:^{
        }];
        // 添加option到queue
        [optionQueue addOperation:option];
    
        // 2.1 option添加依赖(option2完成后才能执行option1)
        NSBlockOperation *option2=[NSBlockOperation blockOperationWithBlock:^{
        }];
        [option addDependency:option2];
        // 删除依赖
        [option removeDependency:option2];
        // 2.2 添加
        [option addExecutionBlock:^{
        }];
    
        // 2.添加匿名blockOption到queue
        [optionQueue addOperationWithBlock:^{
        }];  
    
    
        // 2. 添加InvocationOperation到queue
        // : NSOperation
        NSInvocationOperation *option=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(method) object:nil];
        // 添加option到queue
        [optionQueue addOperation:option];
    
    
        // 2. 添加option数组
        [optionQueue addOperations:@[] waitUntilFinished:true];
    
    queue 队列方法
    
        // queue是否暂停
        BOOL isSuspended=[optionQueue isSuspended];
        // queue暂停
        [optionQueue setSuspended:true];
    
        // queue取消所有option
        [optionQueue cancelAllOperations];
        // 阻塞直到queue所有option完成
        [optionQueue waitUntilAllOperationsAreFinished];
    
        // 设置/获取 name
        [optionQueue setName:@""];
        NSString *name=optionQueue.name;       
    
        // 获取 option数量(readOnly)
        NSUInteger operationCount=optionQueue.operationCount;
        // 获取 最大option数量
        NSInteger maxConcurrentOperationCount=optionQueue.maxConcurrentOperationCount;
    
    option(NSOperation) 方法
    
        // option设置name
        [option setName:@""];
        // option 开始
        [option start];
        // option 取消
        [option cancel];
    
        // 阻塞直到执行完毕
        [option waitUntilFinished];
    
        // 获取优先级
        NSOperationQueuePriority queuePriority=option.queuePriority;
        // 设置优先级
        [option setQueuePriority:NSOperationQueuePriorityHigh];
        /*
        NSOperationQueuePriorityVeryLow = -8L,
        NSOperationQueuePriorityLow = -4L,
        NSOperationQueuePriorityNormal = 0,
        NSOperationQueuePriorityHigh = 4,
        NSOperationQueuePriorityVeryHigh = 8
        */
    
        // option 是否取消
        BOOL isCanceled=[option isCancelled];
        // option 是否正在执行
        BOOL isExecuting=[option isExecuting];
        // option 是否结束
        BOOL isFinished=[option isFinished];
        // option 是否异步
        BOOL isAsy=[option isAsynchronous];
        // 是否就绪
        BOOL isReady=[option isReady];
    
        // 获取依赖列表
        NSArray<NSOperation *> *dependencies=option.dependencies;
    

    自定义NSOperation

    #import <Foundation/Foundation.h>
    @protocol YTOperationCompletionDelegate  
    // 更新UI
    -(void)opCompletion:(NSString *)str;    // 参数看实际情况变化
    @end
    @interface YTMyOperation : NSOperation
    @property (nonatomic,weak) id<YTOperationCompletionDelegate> dele;
    @end
    
    
    #import "YTMyOperation.h"
    @implementation YTMyOperation
    -(void)main{
        //
        [super main];
        
        // 一些操作
        //...
        //
        dispatch_async(dispatch_get_main_queue(), ^{
            if(self.dele){
                [self.dele opCompletion:@"complete"];
            }
        });
    }
    @end
    

    相关文章

      网友评论

        本文标题:iOS基础之多线程

        本文链接:https://www.haomeiwen.com/subject/ezyyextx.html