iOS-Senior10-多线程(子线程创建)

Posted 萌萌的周丽娜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS-Senior10-多线程(子线程创建)相关的知识,希望对你有一定的参考价值。

1.多线程概述

程序:由源代码生成的可执行应用。(eg:QQ.app)

进程:一个正在运行的程序可以看做一个进程。(eg:正在运行的QQ就是一个进程),进程用用独立运行所需的全部资源。

线程:程序中独立运行的代码段。(eg:接收QQ消息的代码)

一个进程是由一或多个线程组成。进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。

1.1单线程

每个正在运行的程序(即进程),至少包含一个线程,这个线程就叫主线程

主线程在程序启动时被创建,用于执行main函数。

只有一个主线程的程序,称为单线程程序。

在单线程程序中,主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行。

1.2多线程

拥有多个线程的程序,称作多线程程序。

ios中允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称作子线程。

可以根据需要开辟若干子线程。

子线程和主线程都是独立的运行单元,各自执行互不影响,因此能够并发执行。

1.3单线程和多线程的区别

单线程程序:只有一个线程,即主线程,代码顺序执行,容易出现代码阻塞(页面假死)。

多线程程序:有多个线程,线程间独立运行,能有效的避免代码阻塞,并且提高程序的运行性能。

注意:iOS中关于UI的添加和刷新必须在主线程中操作。

2.iOS平台下的多线程

2.1NSThread

方法:

//初始化一个子线程,但需要手动开启

- (id) initWithTarget : (id) target selector : (SEL)selector object :(id)argument

//初始化一个子线程,并自动开启

+ (void) detachNewThreadSelector : (SEL) aSelector toTarget : (id) aTarget withObject :(id) anArgument

//开启子线程

start   [operation start]

//取消当前子线程

cancel [operation cancel]

源代码:

//手动开辟子线程

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

[thread start];

//使用NSThread和NSObject实现的开辟线程,系统会自动释放,关不关都行

[thread cancel]; 没有真正取消,而是给线程发送一个信号,通过这个信号进行取消的

[thread exit];  直接将线程退出

//自动开启子线程

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

self.view.backgroundColor = [UIColor redColor] ;

2.2NSObject

//使用performSelectorInBackground开辟子线程

[self performSelectorInBackground :@selector(sayHi) withObject:@"test"];

//在子线程调用的方法里返回主线程,在调用另一个方法

[self performSelectoraOnMainThread:@selector(mainThreadChangeColor) withObject :nil waitUntilDone: YES];

- (void)mainThreadChangeColor {

self.view.backgroudColor = [UIColor magentaColor];

}

方法:

获取当前线程:[NSThread currentThread]

获取主线程   :[NSThread mainThread]

线程休眠2秒 :[NSThread sleepForTimeInterval:2]

注意:

1.每个线程都维护这与自己对应的NSAutoreleasePool对象,将其放在线程栈的栈顶。当线程结束时,会清空自动释放池。

2.为保证对象的及时释放,在多线程方法中需要添加自动释放池。

3.在应用程序打开的时候,系统会自动为主线程创建一个自动释放池。

4.我们手动创建的子线程需要我们手动添加自动释放池。

4.NSOperation和NSOperationQueue

NSOperation类,在NVC中属于M,是用来封装单个任务相关的代码和数据的抽象类。

因为它是抽象的,不能够直接使用这个类,而是使用子类(NSInvocation,NSBlockOperation)来执行实际任务。

NSOperation(含子类),只是一个操作,本身无主线程,子线程之分,可在任意线程中使用。通常与NSOperationQueue结合使用。

//NSInvocationOperation:封装了执行操作的target和要执行的action

 

//NSBlockOperation:封装了需要执行的代码

//NSOperation不能直接进行多线程的创建,需要借助:NSOperationQueue

//在单独使用NSOperation的子类去创建线程的时候,一定要启动才行;

//在使用NSOperation的子类去创建线程的时候,实际上线程没有真正意义上的创建

源程序:

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

 

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"我是block");

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

        NSLog(@"*******%@",[NSThread mainThread]);

    }];

- (void)test {

    NSLog(@"☺");

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

    NSLog(@"mainThread ==  %@",[NSThread mainThread]);

}

    //借助队列,创建子线程

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

    [queue addOperation:operation];

    [queue addOperation:blockOperation]; //有addOperation的时候,就不可以用start,否则会造成崩溃

 

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    //创建队列的对象

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

    //最大的并发数量值

    //当值设置为1的时候,可以叫做串行(单线程)顺序执行

    queue.maxConcurrentOperationCount = 2;

    //当值设置大于1的时候,叫做并行:多条通道同时进行各自的任务

    for (int i = 0; i < 10; i++) {

        //创建10个线程

        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{

            NSLog(@"currentThread == %@,mainThread == %@,%d",[NSThread currentThread],[NSThread mainThread],i);

         }];

        [queue addOperation:blockOperation];

 }

 }

5.GCD(Grand Central Dispatch)使用

简介:GCD是Apple开发的一种多核编程技术。主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。

GCD提供函数实现多线程开发,性能更高,功能也更强大。

它首次发布在Mac OS X 10.6,iOS4及以上也可以用。

任务:具有一定功能的代码段。一般是一个block或者函数。

分发队列:GCD以队列的方式进行工作,FIFO(先进先出)

GCD会根据分发队列的类型,创建合适数量的线程执行队列中的任务。

GCD中两种队列:

1.SerialQueue:一次只执行一个任务。Serial queue通常用于通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然他们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。

2.Concurrent:可以并发地执行多个任务,但是遵守FIFO

#pragma mark - 使用GCD去创建一个串行队列

//第一种:系统提供的创建串行队列的方法

dispatch_queue_t queue = dispatch_get_main_queue();

//在真正的开发中如果需要创建串行队列,比较习惯用这种

//第二种:自己去创建

dispatch_queue_t = dispatch_queue_create(DISPATCH_QUEUE_SERIAL,0);

#pragma mark - 使用GCD去创建并行队列

//第一种:系统的方式

//参数1:优先级(有4个,没有明显的区别)

dispatch_queue_t queue = dispatch_get_globel_queue(DISPATCH_QUEUE_PRIORITY);

//第二种:自己定义的方式(参数和串行不一样)

//参数1:表示创建队列的名字

//参数2:系统提供的宏

//创建队列

dispatch_queue_t queue = dispatch_queue_create("myQueue",DISPATCH_QUEUE_CONCURRENT);

//创建任务

dispatch_async(queue,^{

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

NSLog(@"main == %@",[NSThread MainThread]);

NSLog(@"我是任务一,子进程一");

});

 

dispatch_async(queue,^{

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

NSLog(@"main == %@",[NSThread MainThread]);

NSLog(@"我是任务二,子进程二");

});

 

dispatch_async(queue,^{

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

NSLog(@"main == %@",[NSThread MainThread]);

NSLog(@"我是任务三,子进程三");

});

 

#pragma mark - 几秒之后去做每一件事

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3.0 * NSEC_PER_SEC)),dispatch_get_main_queue(),^{

NSLog(@"3.0秒的时候");

}

);

#pragma mark - 重复向一个队列中添加多个任务

dispatch_queue_t queue = dispatch_queue_create(0,DISPATH_QUEUE_CONCURRENT);

dispatch_apply(100,queue,^(size_t index)) {

NSLog(@"index = %zu",index);

}

#pragma mark - 分组

//创建一个分组

dispatch_group_t group = dispatch_group_create();

//创建一个并行队列

dispatch_queue_t queue = dispatch_queue_create(0,DISPATCH_QUEUE_CONCURRENT);

//创建任务1

dispatch_group_asunc(group,queue,^{

NSLog(@"我是任务1");

});

//创建任务2

dispatch_group_asunc(group,queue,^{

NSLog(@"我是任务2");

});

//创建任务3

dispatch_group_asunc(group,queue,^{

NSLog(@"我是任务3");

});

//用于监听所有任务的执行情况的,所以此功能代码必须放在所有任务之后进行书写的

dispatch_group_notify(group,queue,^{

NSLog(@"我是监听的,最后执行");

});

#pragma mark - 并发中的串行(披着羊皮的狼)

//创建的串行队列

dispatch_queue_t queue = dispatch_queue_create(0,DISPATH_QUEUE_CONCURRENT);

 

dispatch_async(queue,^{

NSLog(@"任务1");

});

 

dispatch_async(queue,^{

 

NSLog(@"任务2");

 

});

 

dispatch_async(queue,^{

NSLog(@"任务3");

});

 

#pragma mark - loadData

//1.url

NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];

//2.session

NSURLSession *session = [NSURLSession sharedSession];

//3.task

NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *_NUllabel data,NSURLResponse *_Nullabel response,NSError *_Nullable error){

if(error == nil){

//处理数据

//回到主线程刷新UI

dispatch_async(dispatch_get_main_queue(),^{

//自己灵活的写点东西吧!!!

})

}

}];

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



以上是关于iOS-Senior10-多线程(子线程创建)的主要内容,如果未能解决你的问题,请参考以下文章

java 多线程子线程唤醒主线程问题

Java总结——通过Callable接口实现多线程,生产者消费者问题,多线下载(复制)文件

八.多进程与多线程

实验二:多线程

Python 多进程多线程效率比较

写出java多线程程序设计中常用类及方法名,并分别说明它们的作用。