多线程初认识

Posted 越自律,越自由!!!

tags:

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

一、多线程的基本概念

二、NSThread

资源竞争原理图

多条线程同时访问同一个资源
    //4.做耗时操作时,多个线程访问同一个资源
    self.ticketCount = 100;
    self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.threadA.name = @"售票员A";
    self.threadB.name = @"售票员B";
    self.threadC.name = @"售票员C";
    //启动线程
    [self.threadA start];
    [self.threadB start];
    [self.threadC start];
//执行方法
- (void)saleTicket{
    //锁:必须是全局唯一性的
    //1.注意加锁的位置
    //2.注意加锁的条件,多线程共享同一块资源
    //3.注意加锁是需要付出代价的,需要耗费性能
    //4.加锁的条件:线程同步
    //如果不加锁的话就会出错
        while (1) {
            @synchronized (self) {
            NSInteger count = self.ticketCount;
            if (count > 0) {
                //耗时操作
                for (NSInteger i = 0; i< 100000; i++) {
                }
                self.ticketCount = count -1;
                NSLog(@"%@卖出去了一张票,还剩下%zd张票",  [NSThread currentThread].name,self.ticketCount);
            }else{
                NSLog(@"票卖完了");
                break;
            }
        }
    }
}

 三、GCD

四、NSOperation

五、代码实例

1.NSOperation

 

 

2.GCD

 //1.异步函数+串行队列,开一条线程,队列中的任务是串行执行的
dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"download1----%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"download2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"download3---%@",[NSThread currentThread]);
    });
//2.异步函数+并行队列,开多条线程,队列中的任务是并行执行的
dispatch_queue_t queue = dispatch_queue_create("current", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"download1----%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"download2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"download3---%@",[NSThread currentThread]);
    });
//3.异步函数+主队列,所有任务都会在主线程中完成,不会开线程
  dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        NSLog(@"download1----%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"download2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"download3---%@",[NSThread currentThread]);
    });
//4.同步函数+串行队列,不会开线程,任务是串行执行的
 dispatch_queue_t queue = dispatch_queue_create("seria", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"downloadload1----%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"downloadload2----%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"download3---%@",[NSThread currentThread]);
    });
//5.同步函数+并行队列,不会开线程,任务是并行执行的
  dispatch_queue_t queue = dispatch_queue_create("seria",DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"download01-------%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"download02-------%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"download03-------%@",[NSThread currentThread]);
    });
//6.//同步函数+主队列= 死锁,如果该线程在子线程中执行,那么所有队列就会在主线程执行
    //同步函数,会崩掉
    //同步函数:立刻马上执行,如果我没有执行完毕,那么后面的也别想执行
    //异步函数:如果我没有执行完毕,那么后面的也可以执行
dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"download01------%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"download02------%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"download03------%@",[NSThread currentThread]);
    });
//7.多线程下载图片
//1.创建子线程下载图片
    //DISPATCH_QUEUE_PRIORITY_DEFAULT 0
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //图片地址
        NSURL *url = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=da0ec79c738da9774e7a8e2f8561d42f/c83d70cf3bc79f3d6842e09fbaa1cd11738b29f9.jpg"];
        //转换成二进制数据
        NSData *data = [NSData dataWithContentsOfURL:url];
        //转换为图片
        UIImage *image = [UIImage imageWithData:data];
        dispatch_async(dispatch_get_main_queue(), ^{
            //更新图片
            self.headImageView.image = image;
        });
    });
//8.延时加载
   //延时加载1
//    [self performSelector:@selector(task) withObject:nil afterDelay:2];
    //延时加载2,用于定时器,repeats是否重复
    [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(task) userInfo:nil repeats:NO];
    //延时加载3,GCD
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"GCD-----%@",[NSThread currentThread]);
    });
//9.栅栏函数
//栅栏函数不能使用全局并发队列
    //什么是dispatch_barrier_async函数
    //毫无疑问,dispatch_barrier_async函数的作用与barrier的意思相同,在进程管理中起到一个栅栏的作用,它等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行,该函数需要同dispatch_queue_create函数生成的concurrent Dispatch Queue队列一起使用
    //dispatch_barrier_async函数的作用
    //如果是3条线程,并发执行的话,1条线程后面加栅栏函数,必须线程1执行完,才会执行线程2,3
    
    //1.实现高效率的数据库访问和文件访问
    //2.避免数据竞争
//获得全局并发队列
//    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t queue = dispatch_queue_create("barrier", DISPATCH_QUEUE_CONCURRENT);
    //异步函数
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 100; i++) {
              NSLog(@"download01--%zd------%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 100; i++) {
              NSLog(@"download02----%zd----%@",i,[NSThread currentThread]);
        }
    });
    //栅栏函数
    dispatch_barrier_async(queue, ^{
        NSLog(@"==========================");
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 100; i++) {
            NSLog(@"download03--%zd------%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 100; i++) {
            NSLog(@"download04----%zd----%@",i,[NSThread currentThread]);
        }
    });
//10.GCD的快速迭代
//1.拿到文件的路径
    NSString *fromPath = @"/Users/xingzai/Desktop/Tools";
    //2.获取文件的路径
    NSString *toPath = @"/Users/xingzai/Desktop/Tool";
    //3.得到目录下所有文件
    NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:fromPath];
    //4.count
    NSInteger count = subPaths.count;
    //5.执行
    dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index) {
       //拼接全路径,文件的路径
        NSString *fullPath = [fromPath stringByAppendingPathComponent:subPaths[index]];
        //拼接全路径,文件剪切到的路径
        NSString *toFullPath = [toPath stringByAppendingPathComponent:subPaths[index]];
        
        //参数一:文件的路径,参数二:文件剪切的位置
        [[NSFileManager defaultManager] moveItemAtPath:fullPath toPath:toFullPath error:nil];
    });
//11.创建组队列
 //1.创建队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //2.创建队列祖
    dispatch_group_t group = dispatch_group_create();
    //3.异步函数
    /**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(@"线程全部执行完了");
    });
//12.合成对象
/**下载图片1,开子线程
       下载图片2,开子线程
       合成图片,并开子线程
     */
    //1.获取群组
    dispatch_group_t group = dispatch_group_create();
    //2.获取并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //3.下载图片,开启子线程
    dispatch_group_async(group, queue, ^{
        NSLog(@"打印当前线程------%@",[NSThread currentThread]);
        //3.1图片地址
        NSURL *url = [NSURL URLWithString:@"http://www.qbaobei.com/tuku/images/13.jpg"];
        //3.2下载二进制数据
        NSData *data = [NSData dataWithContentsOfURL:url];
        //3.3转换图片
        self.imageOne = [UIImage imageWithData:data];
    });
    //下载图片2
    dispatch_group_async(group, queue, ^{
        NSLog(@"-------%@",[NSThread currentThread]);
        //1.图片地址
        NSURL *url = [NSURL URLWithString:@"http://pic1a.nipic.com/2008-09-19/2008919134941443_2.jpg"];
        //2.下载二进制数据
        NSData *data = [NSData dataWithContentsOfURL:url];
        //3.转换图片
        self.imageTwo = [UIImage imageWithData:data];
    });
    //合成图片
    dispatch_group_notify(group, queue, ^{
        
        NSLog(@"-----------%@",[NSThread currentThread]);
        //1.创建图形上下文
        UIGraphicsBeginImageContext(CGSizeMake(320, 640));
        //2.画图形
        [self.imageOne drawInRect:CGRectMake(0, 0, 320, 320)];
        self.imageOne = nil;
        
        [self.imageTwo drawInRect:CGRectMake(0, 320, 320, 320)];
        self.imageTwo = nil;
        //3.根据上下文得到一张图片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        //4.关闭上下文
        UIGraphicsEndImageContext();
        
        NSLog(@"%@",[NSThread currentThread]);
        dispatch_async(dispatch_get_main_queue(), ^{
            //更新UI
            self.headImageView.image = image;
        });
    });
    //由于dispatch_apply函数与dispatch_sync函数相同,会等待处理执行结束,因此推荐在dispatch_async函数中非同步地执行dispatch_apply函数

以上是关于多线程初认识的主要内容,如果未能解决你的问题,请参考以下文章

Linux多线程初体验

多线程认识多线程

android MVP模式初认识-1

Android 编译时注解-初认识

多线程 Thread 线程同步 synchronized

多线程初学习