iOS多线程 GCD NSoperation NSThread

iOS中 多线程技术有三种 NSThread  GCD NSOperation 这三种方式的抽象层度依次有低到高 ,抽象层度越高 也就用着越方便 也是苹果官方推荐的 下面我们依次介绍三种多线程技术

1.NSThread 

   优点:有点量级比较轻

    缺点:需要我们自己去管理线程的整个生命周期,使用起来比较麻烦

    在开发工程中 这个方式我们很少用到 

2.GCD  全称(Grand Central Dispatch) 

   GCD 是一种完全用C语言编写的iOS多线程技术



介绍完三种多线程技术,下面我们就看一下它们是真么用的吧

NSThread:这种多线程技术我们在开发过程中很少使用,所及这里不做过多介绍,简单的介绍一下

@interface HMViewController ()
- (IBAction)btnClick;

@end

@implementation HMViewController

- (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)btnClick {
    // 1.获得当前的线程
    NSThread *current = [NSThread currentThread];
    NSLog(@"btnClick---%@", current);
    
//    NSThread *main = [NSThread mainThread];
//    NSLog(@"btnClick---%@", main);
    
    // 2.执行一些耗时操作 : 创建一条子线程
    [self threadCreate];
}

- (void)run:(NSString *)param
{
    NSThread *current = [NSThread currentThread];
    
    for (int i = 0; i<10000; i++) {
        NSLog(@"%@----run---%@", current, param);
    }
}

/**
 * NSThread的创建方式
 * 隐式创建线程, 并且直接(自动)启动
 */
- (void)threadCreate3
{
    // 在后台线程中执行 === 在子线程中执行
    [self performSelectorInBackground:@selector(run:) withObject:@"abc参数"];
}

/**
 * NSThread的创建方式
 * 创建完线程直接(自动)启动
 */
- (void)threadCreate2
{
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是参数"];
}

/**
 * NSThread的创建方式
 * 1> 先创建初始化线程
 * 2> start开启线程
 */
- (void)threadCreate
{
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"哈哈"];
    thread.name = @"线程A";
    // 开启线程
    [thread start];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"哈哈"];
    thread2.name = @"线程B";
    // 开启线程
    [thread2 start];
}


GCD

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *leftImage;

@property (weak, nonatomic) IBOutlet UIImageView *rightImage;
@property (weak, nonatomic) IBOutlet UIImageView *bigImage;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
 
    
    
    
    //创建一个同步队列  同步队列会按照先进先出的方法一个一个的串发执行任务
    //第一个参数是队列的名称,给创建的同步对列添加一个名称
    //注意这里是c语言语法不能用 “@”
    //第二个参数是对列的属性,一般填写NULL
    dispatch_queue_t queue = dispatch_queue_create("同步队列", NULL) ;
    dispatch_queue_t queue2 = dispatch_queue_create("同步队列", NULL) ;
    
    //获取主线程,主线程是一个同步队列
    //特别注意,不能用串发执行的方法往主线程中添加任务
    //        dispatch_queue_t queue5 = dispatch_get_main_queue() ;
    //创建一个异步队列  异步队列会吧所有任务取出同步执行
    //第一个参数是队列的优先级 是给队列设置优先级
    /**
     DISPATCH_QUEUE_PRIORITY_HIGH         较高的优先级        最先执行
     DISPATCH_QUEUE_PRIORITY_DEFAULT      系统默认的优先级     优先级第二
     DISPATCH_QUEUE_PRIORITY_LOW          较低的优先级        优先级第三
     DISPATCH_QUEUE_PRIORITY_BACKGROUND   这个优先级最低     最后执行
     */
    dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)  ;
    dispatch_queue_t queue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)  ;
    
    //sync 串行执行 不允许创建线程
    //async 并发执行,允许创建线程
    //第一个参数是队列的名称
    //第二个参数是要添加到队列中的事情
    //将任务按照串行执行的方法一个一个的添加到同步对列queue中去, 不会创建线程,切任务是一个一个的执行
    dispatch_sync(queue, ^{
        NSLog(@"111111111111111%@",[NSThread currentThread]) ;
    }) ;
    dispatch_sync(queue, ^{
        NSLog(@"555555555555555%@",[NSThread currentThread]) ;
    }) ;
    //将任务按照串行执行的方法一个一个的添加到异步对列queue1中去, 不会创建线程,任务是多个一起执行
    dispatch_sync(queue1, ^{
        NSLog(@"22222222222222%@",[NSThread currentThread]) ;
    }) ;
    //将任务按照并发执行行的方法一个一个的添加到同步对列queue中去, 会创建一个线程,多个任务会在这个创建的线程内一个一个的执行
    dispatch_async(queue2, ^{
        NSLog(@"33333333333333%@",[NSThread currentThread]) ;
    }) ;
    //将任务按照并发执行行的方法一个一个的添加到异步对列queue中去, 会创建多个线程,多个任务会在这个创建的线程内的执行一起执行
    dispatch_async(queue3, ^{
        NSLog(@"44444444444444444%@",[NSThread currentThread]) ;
    }) ;

    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 *NSEC_PER_SEC));
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",[NSThread currentThread] ) ;
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"%@",[NSThread currentThread] ) ;

    });
    
    dispatch_group_t group = dispatch_group_create() ;
    dispatch_group_async(group, queue, ^{
        NSLog(@"6666666666666group") ;
    }) ;
dispatch_group_async(group, queue1, ^{
     NSLog(@"11111111111111group") ;
}) ;
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"group") ;
    }) ;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"啊哈哈哈哈") ;
    });
    dispatch_group_t group = dispatch_group_create() ;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) ;
    dispatch_queue_t queue1 = dispatch_queue_create("123", NULL) ;
    
    __block  UIImage * image = nil ;
    __block  UIImage * image1 = nil ;
   dispatch_group_async(group, queue, ^{
       NSString * string = @"http://f.hiphotos.baidu.com/image/pic/item/0eb30f2442a7d933fdd1619ba94bd11372f001d8.jpg" ;
       NSURL * URL = [NSURL URLWithString:string] ;
       NSData * data = [NSData dataWithContentsOfURL:URL] ;
       image = [UIImage imageWithData:data] ;
       NSLog(@"image1") ;
   }) ;
  
   dispatch_group_async(group, queue, ^{
       NSString * string = @"http://h.hiphotos.baidu.com/image/pic/item/d058ccbf6c81800a7e38fce4b53533fa838b477e.jpg" ;
       NSURL * URL = [NSURL URLWithString:string] ;
       NSData * data = [NSData dataWithContentsOfURL:URL] ;
       image1 = [UIImage imageWithData:data] ;
       NSLog(@"imag2") ;
   });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        self.leftImage.image = image ;
        self.rightImage.image = image1 ;
    }) ;
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

第二个例子

@interface HMViewController ()
@property (nonatomic, strong) NSThread *thread;
@end

@implementation HMViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];
    self.thread.name = @"线程A";
}

- (void)test
{
    NSLog(@"test - 开始 - %@", [NSThread currentThread].name);
    
//    [NSThread sleepForTimeInterval:5]; // 阻塞状态
    
//    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:5.0];
//    [NSThread sleepUntilDate:date];
    
    for (int i = 0; i<1000; i++) {
        NSLog(@"test - %d - %@", i, [NSThread currentThread].name);
        
        if (i == 50) {
            [NSThread exit];
        }
    }
    
    NSLog(@"test - 结束 - %@", [NSThread currentThread].name);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 开启线程
    [self.thread start];
}



NSOperation 是一种基于GCD开发的技术,它突出了任务的概念,弱化线程的概念。起始NSOperation并不能进行进行多线程任务,而是他的子类方法进行的 一般情况下NSOperation需要与NSOperationQueue结合起来使用 NSOperation是通过子类NSBlockOperation、NSInvocationOperation和自定义的NSOperation的子类来实现,这里只对前两个做介绍,因为前两个基本上能满足我们开发的需求

NSOperation:

创建一个任务

   //创建操作对象
    NSInvocationOperation * operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil] ;
   //添加到任务队列中去
    NSOperationQueue * queue = [[NSOperationQueue alloc]init] ;
    //把任务添加到任务队列中去
    //注意这里需要天加到任务队列中去,要不然需要手动调用  [operation start] 方法开启线程,并且是不会开辟新线程的,无论起了多扫个任务
    [queue addOperation:operation] ;
创建一个NSBlockOperation任务
//创建block任务 默认情况下是不会创建线程
    NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"-----下载图片1-------%@",[NSThread currentThread]) ;
}] ;
    // 注意  blockOperation 如果添加多任务即便是不放在 任务队列 中仍然开辟线程
    [operation addExecutionBlock:^{
        NSLog(@"-----下载图片2-------%@",[NSThread currentThread]) ;
    }] ;
    [operation addExecutionBlock:^{
        NSLog(@"-----下载图片3-------%@",[NSThread currentThread]) ;
        
    }] ;
    [operation addExecutionBlock:^{
        NSLog(@"-----下载图片4-------%@",[NSThread currentThread]) ;
    }] ;
    //开始线程
    [operation start] ;
这样就开辟了三条线程 ,如果添加到OperationQueue,所有的任务都是在子线程内实现的,不在主线程中

NSOperationQueue的一些设置

设置最大的开启线程的数量

 //设置最大并发线程的数量(不包括主线程),如果设置为3 包括主线程在内为4个
    queue.maxConcurrentOperationCount = 3 ;//5以内

取消所有线程

//取消所有的线程
    [queue cancelAllOperations] ;
暂停和开启所有线程
//暂停线程 YES 表示暂停
    [queue setSuspended:YES] ;
    //恢复线程  NO表示继续
    [queue setSuspended:NO] ;
取消单个线程
  [operation1 cancel] ;

设置现成的优先级,优先级越高,执行的可能性越大,被执行的次数越多
//设置优先级
    /*
     NSOperationQueuePriorityVeryLow = -8L,
     NSOperationQueuePriorityLow = -4L,
     NSOperationQueuePriorityNormal = 0,
     NSOperationQueuePriorityHigh = 4,
     NSOperationQueuePriorityVeryHigh = 8
     */
    [operation1 setQueuePriority:NSOperationQueuePriorityHigh] ;
设置线程的依赖关系 
//操作依赖  operation2 做完后才能做 operation1
    //可以在不同队列中添加依赖,但是不能相互依赖
    [operation1 addDependency:operation2] ;
第三个例子

@interface HMViewController ()
/** 剩余票数 */
@property (nonatomic, assign) int leftTicketsCount;
@property (nonatomic, strong) NSThread *thread0;
@property (nonatomic, strong) NSThread *thread1;
@property (nonatomic, strong) NSThread *thread2;
@end

@implementation HMViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 默认有100张
    self.leftTicketsCount = 100;
    
    // 开启多条线程同时卖票
    self.thread0 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread0.name = @"售票员 A";
//    self.thread0.threadPriority = 0.0;
    
    self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread1.name = @"售票员 B";
//    self.thread1.threadPriority = 1.0;
    
    self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread2.name = @"售票员 C";
//    self.thread2.threadPriority = 0.0;
}

/**
 * 卖票
 */
- (void)saleTicket
{
    while (1) {
        @synchronized(self) { // 加锁(只能用一把锁)
            // 1.先检查票数
            int count = self.leftTicketsCount;
            if (count > 0) {
                // 暂停
//                [NSThread sleepForTimeInterval:0.0002];
                
                // 2.票数 - 1
                self.leftTicketsCount = count - 1;
                
                NSThread *current = [NSThread currentThread];
                NSLog(@"%@ 卖了一张票, 剩余%d张票", current.name, self.leftTicketsCount);
            } else {
                // 退出线程
                [NSThread exit];
            }
        } // 解锁
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.thread0 start];
    [self.thread1 start];
    [self.thread2 start];
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值