一、多线程概述
一个程序进入内存运行时就成了一个进程,一个进程包含若干线程,其中必有一个主线程.线程之间运行是独立的.
多线程优势
- 线程之间容易共享内存,进程间不能.
- 充分发挥多核处理器的优势,不同任务分配给不同处理器,进入“并行运算”的状态
- 将耗时、轮询或并发需求高的任务分配到其他线程进行,主线程负责统一更新界面,这样使用户体验更好.
- 多线程劣势
- 占内存(默认住线程1M 子线程512K)
- CPU开销大(一般同时开启线程小于5个).
- 程序设计变得复杂.
- 多线程状态
1.新建(New):分配内存,初始化内部成员变量的值
2.就绪(Runable):创建方法调用的栈和计数器
3.运行(Running):运行状态
4.终止(Exit):线程终止
5.阻塞(Blocked):线程需要暂停一段时间
二、iOS多线程技术
pthread
1.跨平台,可移植
2.使用难度大
3.C语言NSThread
1.面向对象
2.直接操作线程对象
3.Objective-CGCD
1.替代NSThread
2.充分利用多核技术
3.C语言NSOperation
1.基于GCD,更简单
2.更面向对象
3.Objective-C
三、NSThread三种创建线程的方法及阻塞线程的测试
在storyboard里放一个Button和一个Text View(用来测试线程的阻塞)
- 线程一启动就会执行
self
的run:
方法 - 测试阻塞线程时,由于
test
方法处在主线程,Debug栏一直输出,所以拖动文本视图没有任何反应.
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//获取当前、主线程
- (IBAction)ClickBtn:(id)sender {
NSThread *current = [NSThread currentThread];
NSLog(@"Current thread %@ ",current);
NSThread *main = [NSThread mainThread];
NSLog(@"Main thread %@",main);
[self threadCreate1];
//第二种方法 [self threadCreate2];
//第三种方法 [self threadCreate3];
//测试阻塞方法 [self threadTest];
}
//输出当前线程
- (void)run:(NSString *)param{
NSThread *current = [NSThread currentThread];
for(int i = 0; i<10; i++){
NSLog(@"%@ run %@",current,param);
}
}
- (void)threadCreate1{
NSThread *threadA =[[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"线程A参数"];
threadA.name = @"线程A";
[threadA start];
NSThread *threadB =[[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"线程B参数"];
threadB.name = @"线程B";
[threadB start];
}
- (void)threadCreate2{
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"方式2参数"];
}
//隐式创建并启动线程,在后台线程中执行
- (void)threadCreate3{
[self performSelectorInBackground:@selector(run:) withObject:@"方式3参数"];
}
//测试阻塞线程
- (void)threadTest{
NSLog(@"%@",[NSThread currentThread]);
for (int i=0 ; i<10000; i++) {
NSLog(@"-----%d",i);
}
}
@end
四、线程间的安全隐患
- 线程共享会造成资源抢夺,引起数据错乱及安全问题
- 使用
@synchronized(obj)
修饰同步代码块
五、线程间的通信
- 主线程的方法
performSelectorOnMainThread:(SEL) withObject:(id) waitUntilDone:(BOOL)
- 子线程的方法
performSelector:(SEL) onThread:(NSThread *) withObject:(id) waitUntilDone:(BOOL)
GCD(Grand Central Dispatch)
- 基于C语言
- 系统完全管理线程, 无需编写线程代码
一、队列(Dispatch Queue)
- 将长期运行任务(代码块)拆成多个工作单元并添加到队列中,系统代为管理并放到多个线程上执行
- FIFO(先进先出)原则,先进队列先处理,但由于执行时间不同,不一定先结束
- 分类:
1.Serial Dispatch Queue(串行队列): 底层线程池只有一个线程,一次执行一个任务,执行完一个任务才能执行下一个
2.Concurrent Dispatch Queue(并行队列): 底层线程池有多个线程,按FIFO原则执行多任务
二、创建队列
1.获取全局并发队列(Global Concurrent Dispatch Queue)
- 全局并发队列可以按FIFO顺序并行执行多个任务
- 用
dispatch_get_global_queue(long identifier, unsigned long flags)
获取队列
第一个参数用于指定队列优先级,含4个宏定义常量:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 //高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 //默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) //低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN //后台
2.创建串、并行队列(Serial And Concurrent Dispatch Queue)
- 创建队列
dispatch_queue_t
dispatch_queue_create(const char * label, dispatch_queue_attr_t attr)
第一个参数表示队列的字符串
第二个参数控制串并发队列(设为NULL默认串行):
DISPATCH_QUEUE_SERIAL //串行
DISPATCH_QUEUE_CONCURRENT //并行
3.获取主队列
- 主队列在主线程中执行
- 用
dispatch_get_main_queue()
获取主队列
三、提交任务
1.同步添加任务到队列,不具备开启新线程能力,阻塞调用线程直到相应任务完成
- 调用函数
dispatch_sync(dispatch_queue_t queue, ^(void)block) //代码块
dispatch_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work) //函数
2.异步在新线程执行任务,可以让线程池立即执行,调用其他线程做其他事情,应尽可能使用异步.
- 调用函数:
dispatch_async(dispatch_queue_t queue, ^(void)block) //代码块
dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work) //函数
- 在storyboard放两个Button分别执行串、并行任务
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
dispatch_queue_t serialQueue;
dispatch_queue_t globalQueue;
- (void)viewDidLoad {
[super viewDidLoad];
//创建串行队列
serialQueue = dispatch_queue_create("serQ", DISPATCH_QUEUE_SERIAL);
//全局并发队列
globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
//串行异步执行任务
- (IBAction)asynSerial:(id)sender {
dispatch_async(serialQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task1 %d",[NSThread currentThread],i);
}
});
dispatch_async(serialQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task2 %d",[NSThread currentThread],i);
}
});
}
//并行异步执行任务
- (IBAction)asynConcurrent:(id)sender {
dispatch_async(globalQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task1 %d",[NSThread currentThread],i);
}
});
dispatch_async(globalQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task2 %d",[NSThread currentThread],i);
}
});
}
@end
四、单次或重复执行任务
- 单次执行
dispatch_once(dispatch_once_t * predicate, ^(void)block)
- 多次执行
dispatch_apply(size_t iterations, dispatch_queue_t queue, ^(size_t)block)
五、调度队列组
- 将多个block组成一组,监听此组任务是否全部完成.
1.创建队列组对象dispatch_group_create()
2.调度队列组dispatch_group_async()
3.通知:任务执行完后通知执行其他操作dispatch_group_notify()
NSOperation
- NSOperation实例代表一个多线程任务
新建一个继承NSOperation的类.
//Download.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class Download;
//定义代理
@protocol DownloadDelegate <NSObject>
//下载方法
- (void)download:(Download *)operation image:(UIImage *)image;
@end
@interface Download : NSOperation
@property (nonatomic, strong)NSString *url;
//代理属性
@property (nonatomic, weak)id<DownloadDelegate>delegate;
@end
//Download.m
#import "Download.h"
@implementation Download
//重写main方法
- (void)main
{
@autoreleasepool {
NSURL *url = [NSURL URLWithString:self.url];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
NSLog(@"download finished");
if ([self.delegate respondsToSelector:@selector(download:image:)]) {
[self.delegate download:self image:image];
}
}];
}
}
@end
在storyboard中放一个Image View
//ViewController.m
#import "ViewController.h"
#import "Download.h"
@interface ViewController ()<DownloadDelegate>
@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//下载操作
Download *operation = [[Download alloc]init];
operation.delegate = self;
operation.url =@"https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/943ff442182699.57c4298d2eb2a.png" ;
//操作加到队列中
[queue addOperation:operation];
}
//执行操作
- (void)download:(Download *)operation image:(UIImage *)image{
self.imageView.image = image;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
若提示:
App Transport security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
解决方法: