iOS 多线程的一些理解

OC中多线程的操作方法
  • Pthread
  • NSThread
  • GCD
  • NSOperation


  • Pthread基本不会使用(因为太难了-_-),了解下,当做知识面的扩展

  • NSThread在项目中也不怎么使用,使用最多的或许就是调试代码,虽然很简单。。但是没有其他的好用

[NSThread currentThread];//用来查看是当前的方法在哪个线程中
[NSThread mainThread];//得到主线程
//通过NSThread创建子线程通过代码启动
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
//耗时操作最好创建一个子线程
[self performSelectorInBackground:@selector(方法名) withObject:self];
//通过NSThread来创建子线程并启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];

//在子线程需要关于UI的操作,要回到主线程,waitUntilDone参数代表是否在方法执行完之后再向下顺序执行语句
[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

关于NSThread的一些操作

//取消线程
- (void)cancel;

//启动线程
- (void)start;

//判断某个线程的状态的属性
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;

//设置和获取线程名字
-(void)setName:(NSString *)n;
-(NSString *)name;

//获取当前线程信息
+ (NSThread *)currentThread;

//获取主线程信息
+ (NSThread *)mainThread;

//使当前线程暂停一段时间,或者暂停到某个时刻
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;
  • GCD经常使用
    GCD中有两个新的概念:任务和队列

    • 任务:说白了,就是要执行的代码
      任务有两种执行方式:同步执行和异步执行,两种的区别在于会不会堵塞当前线程,同步执行会堵塞当前线程直到block块的代码执行完毕,而异步执行不会

    • 队列:就是要在哪里执行,是串行还是并发,串行就是一个一个的去执行,并发是几个任务可以一起执行,这里有一点要注意:串行和并发都是遵循FIFO的规则(先进先出),不同的是并发执行是CPU将一个一个block块放在不同的线程去完成,所以如果任务很多,它并不会让所有任务同时执行

举个栗子说明一下:这里用到了主队列,主队列是什么?就是主线程,从程序开始就创建的线程,用于UI刷新等等,所以一般耗时的任务还是交给子线程去处理。主队列是一个特殊的串行队列。

/**
 * 同步函数 + 主队列:这样写会造成程序堵塞,造成死锁现象
 */
- (void)syncMain
{
    NSLog(@"syncMain --- Beign");

    //1.获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    //2.将任务加入主队列,这里执行了之后当前线程(主线程)会被堵塞,然后把block块的代码放到主队列执行,但是主线程已经被堵塞,所以程序卡主,造成死锁现象
    dispatch_sync(queue, ^{

        dispatch_async(queue, ^{
            NSLog(@"1-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"2-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"3-----%@", [NSThread currentThread]);
        });
    });
}

/**
 * 异步函数 + 主队列
 */
- (void)asyncMain
{
    NSLog(@"asyncMain --- Begin");

    //1.获取主队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    //2.将任务加入主队列,不会阻塞当前线程,所以执行顺序为:Begin-End-123
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    NSLog(@"asyncMain --- End");
}

/**
 * 同步函数 + 串行队列:不会开辟新线程,会阻塞当前队列(主队列),将block执行完毕
 */
- (void)syncSerial
{
    NSLog(@"syncSerial --- Beign");

    //1.获取串行队列,第一个参数一般是公司的域名,第二个参数为获取哪一个队列
    dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_SERIAL);

    //2.将任务加入队列


    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });


    NSLog(@"syncSerial --- End");
}

/**
 * 异步函数 + 串行队列:会开启新的线程,不会阻塞当前队列
 */
- (void)asyncSerial
{
    NSLog(@"asyncSerial --- Begin");

    //1.获取队列
    dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_SERIAL);

    //2.将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    NSLog(@"asyncSerial --- End");
}

/**
 * 同步函数 + 并行队列:不会开辟新线程,会阻塞当前队列(主队列),把block里面的代码放到当前队列,相当于串行队列
 */
- (void)syncConcurrent
{
    NSLog(@"syncConcurrent --- Beign");

    //1.获取串行队列,第一个参数一般是公司的域名,第二个参数为获取哪一个队列
    dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_CONCURRENT);

    //2.将任务加入队列

    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });


    NSLog(@"syncConcurrent --- End");
}
/**
 * 异步函数 + 并行队列:会开启多条新的线程,不会阻塞当前队列
 */
- (void)asyncConCurrent
{
    NSLog(@"asyncSerial --- Begin");

    //1.获取队列
//    dispatch_queue_t queue = dispatch_queue_create("zj", DISPATCH_QUEUE_CONCURRENT);//自己创建的并行队列
    //系统已经创建好的全局并行队列,一般使用这个不用自己创建,第一个参数为优先级,第二个参数暂时无用为0
//        #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 // 后台

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    //2.将任务加入队列,执行顺序不一定。
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    NSLog(@"asyncSerial --- End");
}

GCD的一些其他用法

//有这么1种需求
//首先:分别异步执行2个耗时的操作
//其次:等2个异步操作都执行完毕后,再回到主线程执行操作
//这时候就可以考虑队列组,
- (void)group
{
    //获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //创建一个队列组
    dispatch_group_t group = dispatch_group_create();

    //下载图片1
    dispatch_group_async(group, queue, ^{

        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];

        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];

        // 生成图片
        self.image1 = [UIImage imageWithData:data];
    });

    //下载图片2
    dispatch_group_async(group, queue, ^{

        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];

        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];

        // 生成图片
        self.image2 = [UIImage imageWithData:data];
    });

    //合成图片
    dispatch_group_notify(group, queue, ^{
        //开启新的图形
        UIGraphicsBeginImageContext(CGSizeMake(100, 100));

        //绘制图片
        [self.image1 drawInRect:CGRectMake(0, 0, 50, 100)];
        [self.image2 drawInRect:CGRectMake(50, 0, 50, 100)];

        //取得图片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

        //结束上下文
        UIGraphicsEndImageContext();

        //回到主线程显示图片
        dispatch_async(dispatch_get_main_queue(), ^{

            self.imageView.image = image;
        });
    });
}

/**
 * 快速迭代,将多个任务自动分发给多个线程,快速完成任务,等到全部完成返回值
 */

- (void)apply
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_apply(10, queue, ^(size_t i) {

        NSLog(@"%lu----%@", i, [NSThread currentThread]);
    });
}

/**
 * 只执行一次的代码,
 */
- (void)once
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"------run");
    });
}

/**
 * 延迟执行
 */
- (void)delay
{
    NSLog(@"touchesBegan-----");

    //设置几秒后执行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"run-------");
    });
}

/**
 * 让排在它前面的任务先执行,然后再执行这个任务
 */
- (void)barrer
{
    dispatch_queue_t queue = dispatch_get_main_queue();

    dispatch_async(queue, ^{
        NSLog(@"1----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2----%@", [NSThread currentThread]);
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"dispatch_barrier_async----3----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"4----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"5----%@", [NSThread currentThread]);
    });
}
  • NSOperation

    /*
     * NSOperation是一个抽象类,不能直接用,直接供开发者用的有两种
     * 1.NSBlockOperation
     * 2.NSInvocationOperation
     * 3.开发者可以继承NSOperation自定义任务
     */
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
        //调用NSBlockOperation的方法
    //    [self blockOperation];
        //调用NSInvocationOperation的方法
    //    [self invacationOperation];
    
        //让队列执行,如果暂停就执行,如果执行就暂停
    //    if (self.queue.isSuspended)
    //    {
    //        self.queue.suspended = NO;
    //    }
    //    else
    //    {
    //        self.queue.suspended =YES;
    //    }
        //取消所有操作
    //    [self.queue cancelAllOperations];
        //依赖操作
        [self operationWithDependency];
    
    }
    
    //NSBlockOperation的使用比较方便的使用
    - (void)blockOperation
    {
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    
            //只执行这一句的话在主线程执行,NSOperation对队列的掌控比较好,自动分配队列
            NSLog(@"任务1_____%@", [NSThread currentThread]);
        }];
    
        //还可以对这个操作添加额外的线程(这时候自动在子线程执行这些任务)
        [op addExecutionBlock:^{
            NSLog(@"任务2_____%@", [NSThread currentThread]);
        }];
        [op addExecutionBlock:^{
            NSLog(@"任务3_____%@", [NSThread currentThread]);
        }];
        [op addExecutionBlock:^{
            NSLog(@"任务4_____%@", [NSThread currentThread]);
        }];
    
        //写完任务后需要任务开始
        [op start];
    }
    
    //NSInvocationOperation的使用还是比较麻烦的一般不去使用
    - (void)invacationOperation
    {
        //用来执行一个方法和[self performSelector:@selector(run) withObject:nil];很像,都是在主线程执行
        NSInvocationOperation *opInvocation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    
        [opInvocation start];
    }
    
    - (void)run
    {
        NSLog(@"invocationTask______%@", [NSThread currentThread]);
    }
    
    
    /*
     * NSOperation还可以创建队列来执行操,用最大并发操作数来设置并行或者串行队列
     * 可以向队列里面添加操作有三种
     * 1.创建NSInvocationOperation对象添加
     * 2.创建NSBlockOperation对象添加
     * 3.直接以下面这种方式添加(NSBlockOperation的简单方式)
     */
    - (void)OperationQueue
    {
        //创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        //设置最大并发操作数
        /*
         * 默认值是-1,自动调配队列
         * 设置1时,就是串行队列
         * 设置>1时,就是并行队列
         */
        queue.maxConcurrentOperationCount = -1;
    
        //添加操作
        [queue addOperationWithBlock:^{
    
            NSLog(@"操作1________%@",[NSThread currentThread]);
            /*
             * NSOperationQueue 可以选择挂起队列或者恢复队列或者取消操作
             * suspended 的值决定了暂停(挂起)或者恢复
             * YES:挂起队列 NO:恢复队列
             * 调用方法 cancelAllOperations 取消所有操作
             * 取消所有操作注意:取消操作后需要把当前的操作执行完毕后,取消排在后面的操作
             */
    
            //可以用一个耗时操作来验证一下
    //        for (NSInteger i = 0; i < 5000; ++i)
    //        {
    //            NSLog(@"操作1____%zd____%@", i, [NSThread currentThread]);
    //        }
        }];
    
        [queue addOperationWithBlock:^{
    
            NSLog(@"操作2________%@",[NSThread currentThread]);
    //        for (NSInteger i = 0; i < 5000; ++i)
    //        {
    //            NSLog(@"操作2____%zd____%@", i, [NSThread currentThread]);
    //        }
        }];
    
        [queue addOperationWithBlock:^{
    
            NSLog(@"操作3________%@",[NSThread currentThread]);
    //        for (NSInteger i = 0; i < 5000; ++i)
    //        {
    //            NSLog(@"操作3____%zd____%@", i, [NSThread currentThread]);
    //        }
        }];
    
        NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"操作4________%@",[NSThread currentThread]);
        }];
    
        [blockOperation addExecutionBlock:^{
            NSLog(@"操作5________%@",[NSThread currentThread]);
        }];
    
        [queue addOperation:invocationOperation];
        [queue addOperation:blockOperation];
    
        self.queue = queue;
    }
    
    /*
     * 在一个队列中,可以设置依赖,就像GCD中的队列组,让某个操做在一个或几个操作之后进行
     */
    - (void)operationWithDependency
    {
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        __block UIImage *image1 = nil;
        // 下载图片1
        NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{
    
            // 图片的网络路径
            NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
    
            // 加载图片
            NSData *data = [NSData dataWithContentsOfURL:url];
    
            // 生成图片
            image1 = [UIImage imageWithData:data];
        }];
    
        __block UIImage *image2 = nil;
        // 下载图片2
        NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{
    
            // 图片的网络路径
            NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
    
    
            // 加载图片
            NSData *data = [NSData dataWithContentsOfURL:url];
    
            // 生成图片
            image2 = [UIImage imageWithData:data];
        }];
    
        // 合成图片
        NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{
            // 开启新的图形上下文
            UIGraphicsBeginImageContext(CGSizeMake(100, 100));
    
            // 绘制图片
            [image1 drawInRect:CGRectMake(0, 0, 50, 100)];
            image1 = nil;
    
            [image2 drawInRect:CGRectMake(50, 0, 50, 100)];
            image2 = nil;
    
            // 取得上下文中的图片
            UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
            // 结束上下文
            UIGraphicsEndImageContext();
    
            // 回到主线程
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                self.imageView.image = image;
            }];
        }];
        //给合成的操作添加依赖
        [combine addDependency:download1];
        [combine addDependency:download2];
    
        [queue addOperation:download1];
        [queue addOperation:download2];
        [queue addOperation:combine];
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值