Pthread
//1.创建线程对象
pthread_t thread;
//2.创建线程
/*
第一个参数:线程对象 传递地址
第二个参数:线程的属性 NULL
第三个参数:指向函数的指针
第四个参数:函数需要接受的参数
*/
pthread_create(&thread, NULL, task, NULL);
void *task(void *param)
{
for (NSInteger i = 0; i<10000; i++) {
NSLog(@"%zd----%@",i,[NSThread currentThread]);
}
// NSLog(@"%@--------",[NSThread currentThread]);
return NULL;
}
NSThread
//1.创建线程
/*
第一个参数:目标对象 self
第二个参数:方法选择器 调用的方法
第三个参数:前面调用方法需要传递的参数 nil
*/
XMGThread *threadA = [[XMGThread alloc]initWithTarget:self selector:@selector(run:) object:@"ABC"];
//设置属性
threadA.name = @"线程A";
//设置优先级 取值范围 0.0 ~ 1.0 之间 最高是1.0 默认优先级是0.5
threadA.threadPriority = 1.0;
//2.启动线程
[threadA start];
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"分离子线程"];
3.开启后台线程
[self performSelectorInBackground:@selector(run:) withObject:@"开启后台线程"];
线程安全
while (1) {
//锁:必须是全局唯一的
//1.注意枷锁的位置
//2.注意枷锁的前提条件,多线程共享同一块资源
//3.注意加锁是需要代价的,需要耗费性能的
//4.加锁的结果:线程同步
@synchronized(self) {
//线程1
//线程2
//线程3
NSInteger count = self.totalCount;
if (count >0) {
for (NSInteger i = 0; i<1000000; i++) {
}
self.totalCount = count - 1;
//卖出去一张票
NSLog(@"%@卖出去了一张票,还剩下%zd张票", [NSThread currentThread].name,self.totalCount);
}else
{
NSLog(@"不要回公司上班了");
break;
}
}
}
GCD
1.异步函数+并发队列:会开启多条线程,队列中的任务是并发执行
//获得全局并发队列
/*
第一个参数:优先级
第二个参数:
*/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"---satrt----");
//2.1>封装任务2>添加任务到队列中
/*
第一个参数:队列
第二个参数:要执行的任务
*/
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
2.异步函数+串行队列:会开线程,开一条线程,队列中的任务是串行执行的
//1.创建队列
dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);
//2.封装操作
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
3.同步函数+并发队列:不会开线程,任务是串行执行的
//1.创建队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---start---");
//2.封装任务
dispatch_sync(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
4.同步函数+串行队列:不会开线程,任务是串行执行的
//1.创建队列
dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_SERIAL);
//2.封装任务
dispatch_sync(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
5.异步函数+主队列:所有任务都在主线程中执行,不会开线程
//1.获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//2.异步函数
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
//同步函数+主队列:死锁
//注意:如果该方法在子线程中执行,那么所有的任务在主线程中执行,
-(void)syncMain
{
//1.获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"start----");
//2.同步函数
//同步函数:立刻马上执行,如果我没有执行完毕,那么后面的也别想执行
//异步函数:如果我没有执行完毕,那么后面的也可以执行
dispatch_sync(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"download2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"download3----%@",[NSThread currentThread]);
});
NSLog(@"end---");
}
死锁解释
先请看下面这张图,相信大家都知道会死锁,为什么呢。
往串行队列添加的任务需要等到串行队列前面的任务都执行完毕才会开始执行。抛开你所谓的堵塞概念,我不认为这是适合的描述。对于在主线程,你可以认为每一语句都是将任务插入主队列。调用dispatch_sync这个函数相当于将一个任务插入主队列,这个函数的作用是将一个任务插入指定队列,当这个函数里的Block执行完毕以后,这个函数才会返回,即这个调用这个dispatch_sync的任务结束,主队列继续往下添加任务。我上面说了,串行的任务添加后需要等前面的任务都执行完才会执行的。所以Block里的任务需要等dispatch_sync这个调用执行完才会执行,然而dispatch_sync并不会返回。
第二个是创建了一个空的串行队列,dispatch_sync这个是主队列添加的任务,工作是将一个任务添加到这个新创建的队列上,由于指定的队列前面没有其他任务,所以这个任务先执行,然后返回,dispatch_sync返回,主队列继续往下添加任务。
线程通讯
//1.创建子线程下载图片
//DISPATCH_QUEUE_PRIORITY_DEFAULT 0
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//1.1 确定url
NSURL *url = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=da0ec79c738da9774e7a8e2f8561d42f/c83d70cf3bc79f3d6842e09fbaa1cd11738b29f9.jpg"];
//1.2 下载二进制数据到本地
NSData *imageData = [NSData dataWithContentsOfURL:url];
//1.3 转换图片
UIImage *image = [UIImage imageWithData:imageData];
NSLog(@"download----%@",[NSThread currentThread]);
//更新UI
// dispatch_async(dispatch_get_main_queue(), ^{
dispatch_sync(dispatch_get_main_queue(), ^{
self.imageView.image = image;
NSLog(@"UI----%@",[NSThread currentThread]);
});
});
常用函数
/*
第一个参数:DISPATCH_TIME_NOW 从现在开始计算时间
第二个参数:延迟的时间 2.0 GCD时间单位:纳秒
第三个参数:队列
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
NSLog(@"GCD----%@",[NSThread currentThread]);
});
//一次性代码
//不能放在懒加载中的,应用场景:单例模式
-(void)once
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"---once----");
});
}
栅栏函数
//0.获得全局并发队列
//栅栏函数不能使用全局并发队列
//dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
//1.异步函数
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
}
});
//栅栏函数
dispatch_barrier_async(queue, ^{
NSLog(@"+++++++++++++++++++++++++++++");
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download3-%zd-%@",i,[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<100; i++) {
NSLog(@"download4-%zd-%@",i,[NSThread currentThread]);
}
});
download4 download3 会在 download1 download2后执行
快速迭代
//开子线程和主线程一起完成遍历任务,任务的执行时并发的
-(void)applyDemo
{
/*
第一个参数:遍历的次数
第二个参数:队列(并发队列)
第三个参数:index 索引
*/
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%zd---%@",index,[NSThread currentThread]);
});
}
GCD另一种写法
/*
第一个参数:队列
第二个参数:参数
第三个参数:要调用的函数的名称
*/
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
队列组
第一种
//1.创建队列
dispatch_queue_t queue =dispatch_get_global_queue(0, 0);
//2.创建队列组
dispatch_group_t group = dispatch_group_create();
//3.异步函数
/*
1)封装任务
2)把任务添加到队列中
dispatch_async(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
*/
/*
1)封装任务
2)把任务添加到队列中
3)会监听任务的执行情况,通知group
*/
dispatch_group_async(group, queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"3----%@",[NSThread currentThread]);
});
//拦截通知,当队列组中所有的任务都执行完毕的时候回进入到下面的方法
dispatch_group_notify(group, queue, ^{
NSLog(@"-------dispatch_group_notify-------");
});
// NSLog(@"----end----");
第二种
//1.创建队列
dispatch_queue_t queue =dispatch_get_global_queue(0, 0);
//2.创建队列组
dispatch_group_t group = dispatch_group_create();
//3.在该方法后面的异步任务会被纳入到队列组的监听范围,进入群组
//dispatch_group_enter|dispatch_group_leave 必须要配对使用
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
//离开群组
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
//离开群组
dispatch_group_leave(group);
});
//拦截通知
//问题?该方法是阻塞的吗? 内部本身是异步的
// dispatch_group_notify(group, queue, ^{
// NSLog(@"-------dispatch_group_notify-------");
// });
//等待.死等. 直到队列组中所有的任务都执行完毕之后才能执行
//阻塞的
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"----end----");
单利实现
ARC下
/0.提供全局变量
static XMGTool *_instance;
//1.alloc-->allocWithZone
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//加互斥锁解决多线程访问安全问题
// @synchronized(self) {
// if (_instance == nil) {
// _instance = [super allocWithZone:zone];
// }
// }
//本身就是线程安全的
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
//2.提供类方法
+(instancetype)shareTool
{
return [[self alloc]init];
}
//3.严谨
-(id)copyWithZone:(NSZone *)zone
{
return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
return _instance;
}
MRC下:
#if __has_feature(objc_arc)
//条件满足 ARC
#else
// MRC
-(oneway void)release
{
}
-(instancetype)retain
{
return _instance;
}
//习惯
-(NSUInteger)retainCount
{
return MAXFLOAT;
}
#endif
NSOperation
基本使用
//1.创建操作,封装任务
/*
第一个参数:目标对象 self
第二个参数:调用方法的名称
第三个参数:前面方法需要接受的参数 nil
*/
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download2) object:nil];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download3) object:nil];
//2.启动|执行操作
[op1 start];
[op2 start];
[op3 start];
上面的使用运行在主线程
//1.创建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}];
//追加任务
//注意:如果一个操作中的任务数量大于1,那么会开子线程并发执行任务(就是此列加block任务开线程,不加跟上面一样)
//注意:不一定是子线程,有可能是主线程
[op3 addExecutionBlock:^{
NSLog(@"4---%@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"5---%@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"6---%@",[NSThread currentThread]);
}];
//2.启动
[op1 start];
[op2 start];
[op3 start];
NSOperationQueue
//1.创建操作,封装任务
/*
第一个参数:目标对象 self
第二个参数:调用方法的名称
第三个参数:前面方法需要接受的参数 nil
*/
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download2) object:nil];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download3) object:nil];
//2.创建队列
/*
GCD:
串行类型:create & 主队列
并发类型:create & 全局并发队列
NSOperation:
主队列: [NSOperationQueue mainQueue] 和GCD中的主队列一样,串行队列
非主队列: [[NSOperationQueue alloc]init] 非常特殊(同时具备并发和串行的功能)
//默认情况下,非主队列是并发队列
*/
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//3.添加操作到队列中
[queue addOperation:op1]; //内部已经调用了[op1 start]
[queue addOperation:op2];
[queue addOperation:op3];
block的那种用法一样