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