多线程

// 多线程
   
// 单线程 : 在应用程序启动的时候 , 会自动创建一个线程。该线程为主线程。只有一个主线程的应用程序为单线程应用程序。在主线程的代码会顺序执行。
   
// 单线程程序的问题 : 在程序运行的过程中难免会需要请求数据、解析数据等等很多耗时的任务。这时如果把所有的任务都放在主线程中执行会造成程序的假死现象 , 用户交互不好。
   
// 为了提高用户的交互性 , 可以采用多线程。
   
// 多线程 : 即程序中不仅仅有一个主线程。这些子线程主要用来进行一些复杂的工作。
   
// 使用多线程注意事项 : 不管开辟的多少个子线程 , 最终 UI 界面的刷新和展示 ( 即所有对 UI 的操作 ) 都需要回到主线程中执行。 ==>> 问题 : 如何从子线程回到主线程 ?
   
// 使用多线程的优缺点 :
              
// 优点 : 可以防止主线程阻塞 , 提用户交互性。
              
// 缺点 : 1. 在开辟子线程的时候需要耗费一定的资源。
               //      2. 不管开辟了多少个子线程最终要回到主线程 , 这时也需要耗
                                                      CPU 性能。 
               //      3. 子线程开辟过多少会造成代码可读性比较差。
   
//  问题一 : 如何从子线程回到主线程 :
    
// 1.NSObject 对应的方法 :performSelectorOnMainThread
     // 2.dispatch_async(dispatch_get_main_queue(), ^{});


  /******************** 第一种方式 NSThread********************/
   
// 获取当前的线程 (thread)
   
NSLog ( @"mainThread:%@" , [ NSThread currentThread ]);
   
//  initWithTarget:selector:object: 参数含义如下 :
     
// 1. 目标
     
// 2. 方法名
     
// 3. 方法对于的参数
//  在使用下列方法时需要注意该方法不会自动开辟子线程执行方法 , 需要手动调用 start 开启。 ( 开辟子线程 )
//    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(calculate:) object:self.NumberTF.text];
//    // 开启
//    [thread1 start];
   
   
// 这个方法使用会立即跳到子线程 , 不需要手动 Start
    [NSThread detachNewThreadSelector:@selector(calculate:) toTarget:self withObject:self.NumberTF.text];

    // 在子线程里加载图片 , 然后回到主线程显示图片
   
/*************** 方式二使用 NSObject*****************/
   
NSURL *url = [ NSURL URLWithString : kURL ];
#pragma mark - 该方法是 NSObject 的方法 , 凡是继承 NSObject 的类都可以使用该方法。该方法调用几次就会开辟几个子线程。 ==> 问题 : 如果不同线程争夺同一个资源 , 咋办 ?
//    @synchronized(<#token#>) {     // 线程锁方法一
//        <#statements#>
//    }
    [self performSelectorInBackground:@selector(downloadMyImage:) withObject:url]; // 开启子线程

    /************ 方式三 使用 NSOperationQueue*************/
   
// NSOperationQueue: 操作队列。用来管理一组操作 (NSOperation)
   
// 注意事项 :NSOperationQueue 开辟线程的个数是由系统决定的。不是由操作的个数决定的。 ( ⭐️⭐️⭐️⭐️⭐️ ) ==> 面试题 !!!
   
// 创建两个 NSOperation(NSBlockOperation\ NSInvocation)
   
NSBlockOperation *blockOp = [ NSBlockOperation blockOperationWithBlock :^{
       
NSLog ( @"blockThread:%@" , [ NSThread currentThread ]);
    }];
   
NSInvocationOperation *invocationOp = [[ NSInvocationOperation alloc ] initWithTarget : self selector : @selector (calculate:) object : @"50" ];
   
   
NSOperationQueue *queue = [[ NSOperationQueue alloc ] init ];
#pragma mark - 下列方法中参数的含义 :
    // 1. 操作对应的数组
   
// 2.BOOL: 如果给的是 YES, 那么会阻塞当前线程 , 直到操作队列里面所有的操作被执行完 , 当前线程才不会被阻塞。
//  如果给的是 NO, 那么不会阻塞当前线程。
//  可能会产生的问题 : 如果给的是 YES, 而且卡死的是主线程。那么在操作中如果需要对 UI 进行操作需要返回到主线程中去执行代码。这时程序就会出现死锁 ( 一直出不来 , 按键也一直不能再次点击 )
   
// 设置最大并发数为 1.( 当前在操作队列中正在运行的任务只有一个。与线程个数无关。 )
   
// 如果设置最大并发数为 1, 那么可以实现线程同步。
   
// 线程同步 : 只有当一个线程中的任务执行完毕之后 , 才能执行另外一个线程的任务。
    queue.
maxConcurrentOperationCount = 1 ;
    [queue addOperations:@[blockOp, invocationOp] waitUntilFinished:NO];

/************************* 方式四 GCD************************/
// GCD 的核心是分发队列。
// 分发队列有两种形式 :
      
// 串行队列 : 一次只能执行一个任务。如果有多个串行队列那么每个队列中的任务都是同步执行的 , 但是队列之间可以并发执行 ( 互不干扰 )
      
// 并行队列 : 并发的执行多个任务。但是 FIFO.( 只支持先进 , 并不一定先出。 )
- (
IBAction )serialQueue:( id )sender {
   
// 串行队列有两种形式 :
       
// 1. 系统提供的 :dispatch_async(dispatch_get_main_queue: 主队列 ==>> 在主线程中。
   
dispatch_async ( dispatch_get_main_queue (), ^{
       
NSLog ( @" 下载图片 :%@" , [ NSThread currentThread ]);
    });
       
// 2. 自己创建的 ( 自己创建的会再子线程 )
   
dispatch_queue_t queue = dispatch_queue_create ( "com.fy.queue1" , DISPATCH_QUEUE_SERIAL );
   
dispatch_async (queue, ^{
       
NSLog ( @"thread:%@" , [ NSThread currentThread ]); // 子线程中
    });
   
// 串行是顺序执行
   
dispatch_async (queue, ^{
       
NSLog ( @" 小米出生了 " );
    });
   
dispatch_async (queue, ^{
       
NSLog ( @" 小米上学了 " );
    });
   
dispatch_async (queue, ^{
       
NSLog ( @" 小米结婚了 " );
    });
   
dispatch_async (queue, ^{
       
NSLog ( @" 小米有宝宝了 " );
    });
   
}

- (
IBAction )concurrentQueue:( id )sender {
   
// 并行队列有两种 :
       
// 1. 系统提供的 ( 也是子线程 )
   
dispatch_async ( dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 ), ^{
       
NSLog ( @"======:%@" , [ NSThread currentThread ]);
    });
   
       
// 2. 自己创建的
   
dispatch_queue_t concurrentQueue = dispatch_queue_create ( "com.fy.concurrentQueue" , DISPATCH_QUEUE_CONCURRENT );
   
dispatch_async (concurrentQueue, ^{
       
NSLog ( @"thread:%@" , [ NSThread currentThread ]); // 子线程中
    });
   
// 并行队列与顺序没有关系 , 是无序的
   
dispatch_async (concurrentQueue, ^{
       
NSLog ( @" 小米出生了 " );
    });
   
dispatch_async (concurrentQueue, ^{
       
NSLog ( @" 小米上学了 " );
    });
   
dispatch_async (concurrentQueue, ^{
       
NSLog ( @" 小米结婚了 " );
    });
   
dispatch_async (concurrentQueue, ^{
       
NSLog ( @" 小米有宝宝了 " );
    });
}

// 使用 GCD
- (
IBAction )useGCD:( id )sender {
   
dispatch_queue_t myQueue = dispatch_queue_create ( "com.fy.myQueue" , DISPATCH_QUEUE_SERIAL );
   
dispatch_async (myQueue, ^{
       
UIImage *image = [ UIImage imageWithData :[ NSData dataWithContentsOfURL :[ NSURL URLWithString : kImage ]]];
       
dispatch_async ( dispatch_get_main_queue (), ^{
           
self . imageView . image = image;
        });
    });
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值