04 多线程

1.多线程的基本概念

每一个程序都有一个主线程,程序启动时创建(调用main来启动)

主线程的生命周期是和应用程序绑定的,程序结束时,主线程也就停止

多线程技术表示,一个应用程序有多个线程,使用多线程能提供cup的使用率,防止主线程阻塞

任何有可能堵塞主线程的任务不要在主线程执行(访问网络)

注意:

线程使用不是无节制的

只有主线程有直接修改UI的能力(子线程与主线程通信)

2.多线程技术


3.线程的创建与启动


 01.NSThread:

- (void)viewDidLoad {
    
    [super viewDidLoad];
    // 开启了一个子线程,主线程继续执行,子线程也继续执行
    // 1、[NSThread detachNewThreadSelector:@selector(test1) toTarget:self withObject:nil];
    
    // 2、alloc 创建线程需要手动开启
    /*
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test1) object:nil];
    // 手动开启线程
    [thread start];
    
    [self test2];
    */
    
    // 3、设置图片
    imgView = [[UIImageView alloc] initWithFrame:CGRectMake(60, 100, 200, 200)];
    imgView.backgroundColor = [UIColor redColor];
    [self.view addSubview:imgView];
    
    NSLog(@"current Thread : %@", [NSThread currentThread]);
}

- (void)refreshUI:(UIImage *)image
{
    imgView.image = image;
}

#pragma mark - 设置图片
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //[NSThread detachNewThreadSelector:@selector(subThread:) toTarget:self withObject:@(2)];
    
    // 开启后台线程(子线程)
    [self performSelectorInBackground:@selector(subThread:) withObject:nil];
}

- (void)subThread:(NSNumber *)number
{
    // ARC
    // 因为在子线程创建的自动释放的对象,是不能够入主线程的自动释放中的
    @autoreleasepool {
        
        NSLog(@"current Thread : %@", [NSThread currentThread]);
        
        // 耗时操作
        NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/w%3D2048/sign=110ed40be9f81a4c2632ebc9e3126159/b3b7d0a20cf431add6d225464936acaf2edd9848.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        // 刷新UI 错误了!不能在子线程中刷新UI的事情,很有可能会崩溃
        //imgView.image = image;
        
        // 只能在主线程做刷新UI,涉及到主线程和子线程通信(NSObject中方法)
        /**
         *  从子线程回到主线程
         *  (1)回到主线程的方法
         *  (2)传递的参数可以为空
         *  (3)YES,必须等待主线程refreshUI:
         NO,不需要等待
         */
        [self performSelectorOnMainThread:@selector(refreshUI:) withObject:image waitUntilDone:YES];
        
        // 假设子线程还有若干事情
        // YES,必须走完refreshUI:
        // NO,主线程继续执行,子线程也接着执行
    }
}

#pragma mark - 开启了线程了,打印交替进行了(2条执行路径)
- (void)test1
{
    for (int i = 0; i < 1000; i++) {
        
        // 性能开销比较大
        NSLog(@"task 1: %d", i);
    }
}

- (void)test2
{
    for (int i = 0; i < 100; i++) {
        
        // 性能开销比较大
        NSLog(@"task 2: %d", i);
    }
}

#pragma mark - NSLog 性能开销比较大
- (IBAction)task1:(UIButton *)sender {
    
    for (int i = 0; i < 10000; i++) {
        
        // 性能开销比较大
        //NSLog(@"task 1: %d", i);
    }
    
    //NSLog(@"task 1");
}

- (IBAction)task2:(UIButton *)sender {

    for (int i = 0; i < 100000; i++) {
        
    }
    
    //NSLog(@"task 2");
    
}

NSThread的常用方法:

//获取当前线程对象
+ (NSThread *)currentThread;
//使当前线程睡眠指定的时间,单位为秒
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//退出当前线程
+ (void)exit;
//判断当前线程是否为主线程
+ (BOOL)isMainThread
//启动该线程
- (void)start


还学到了:

// 如果我们DEBUG模式【调试】(RELEASE模式【发布】)
/**
 *  源代码
 *  编译(目标代码).o
                                     / Debug   系统库文件(冗余,多)
 *  链接(多个文件,用户定义文件,系统库文件)
 *                                   \ Release 系统库文件(少)
 
 */

#ifdef DEBUG

    #define MYLog(...) NSLog(__VA_ARGS__)

#else

    #define MYLog(...)

#endif



02.NSOperation

@interface ViewController ()
{
    NSOperationQueue *queue;
}

@end

@implementation ViewController

/**
 *  阻塞主线程 - 耗时的操作
 */

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    // 同步:先做A【耗时操作、界面卡顿】,再去做B

    // 异步:同时进行A、B和操作
    
    // 1 同步操作
    /*
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self
                                                                      selector:@selector(op1)
                                                                        object:nil];
    // 开启了操作,调用指定的方法
    [op1 start];
    */
    
    
    // NSOperation 抽象类,不实例化
    /**
     * (1) NSInvocationOperation
     * (2) NSBlockOperation
     */
    // 2 异步操作
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op1) object:nil];
    // 设置优先级
    [op1 setQueuePriority:NSOperationQueuePriorityVeryLow];

    NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op2) object:nil];
    [op2 setQueuePriority:NSOperationQueuePriorityVeryHigh];

    // 当子线程完成时
    [op2 setCompletionBlock:^{
        //
        NSLog(@"YES : %@", [NSThread currentThread]);
    }];
    
    NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op3) object:nil];
    [op3 setQueuePriority:NSOperationQueuePriorityLow];
    
    NSInvocationOperation *op4 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op4) object:nil];
    [op4 setQueuePriority:NSOperationQueuePriorityNormal];
    
    NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
        
        //NSLog(@"op2 : %@", [NSThread currentThread]);
        
        for (int i = 0; i < 10; i++) {
            NSLog(@"block op5 is :%d", i);
        }
    }];
    [op5 setQueuePriority:NSOperationQueuePriorityHigh];
    
    // 一旦将操作对象放入“操作队列”中,这个操作就变了异步操作(开启一个线程)
    // 此外,我们不需要将“操作”对象手动开启,当这个操作加入到“队列”中,事情开始了
    queue = [[NSOperationQueue alloc] init];
    // 设置队列的并发数
    [queue setMaxConcurrentOperationCount:1];
    //[queue addOperation:op1];
    //[queue addOperation:op2];
    //[queue addOperation:op3];
    //[queue addOperation:op4];
    //[queue addOperation:op5];
     
    NSArray *ops = @[op1, op2, op3, op4, op5];
    // YES 阻塞当前线程(主线程),必须等待所有“操作队列”结束之后
    // NO  不会阻塞主线程
    [queue addOperations:ops waitUntilFinished:NO];
    
    // 3 设置依赖关系
    /*
    NSBlockOperation *op7 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"hello op7");
    }];
    
    NSBlockOperation *op8 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"hello op8");
        // 根据栏目ID,请求具体内容
    }];
    
    NSBlockOperation *op9 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"hello op9");
        // 先请求栏目数据 NSArray【model】
    }];
    
    // 设置依赖关系,切记不要“循环依赖”  得出op9 op8 op7
    [op7 addDependency:op8];
    [op8 addDependency:op9];
    queue = [[NSOperationQueue alloc] init];
    [queue addOperations:@[op7, op8, op9] waitUntilFinished:NO];
    */
}



- (void)op1
{
    //NSLog(@"op1 : %@", [NSThread currentThread]);
    
    for (int i = 0; i < 10; i++) {
        
        NSLog(@"op1 is : %d", i);
        
    }
    //子线程与主线程之间通信
    //[self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:YES];
    
    // 回到主线程
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        
        NSLog(@"hello %@", [NSThread currentThread]);
    }];
}

- (void)op2
{
    for (int i = 0; i < 10; i++) {
        
        NSLog(@"op2 is : %d", i);
        
    }
}

- (void)op3
{
    for (int i = 0; i < 10; i++) {
        
        NSLog(@"op3 is : %d", i);
        
    }
}

- (void)op4
{
    for (int i = 0; i < 10; i++) {
        
        NSLog(@"op4 is : %d", i);
        
    }
}

同步是无法取消的。

还学了线程锁:

// synchronized 锁的作用
    /*
    @synchronized(self) {
        
        if (_allTickts > 0) {
            
            // 线程睡眠(测试)
            [NSThread sleepForTimeInterval:2];
            
            _allTickts--;
            
            NSLog(@"_allTickts : %d", _allTickts);
        }else {
            
            NSLog(@"票已经卖了");
        }
    }*/
    
    // NSLock
    /*
    [_lock lock];

03.GCD

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //[self gcd1];
    
    //[self gcd2];
    
    [self gcd3];
}

- (void)gcd3
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("com.wxhl.c", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"t 1: %@", [NSThread currentThread]);
        
        for (int i = 0; i < 20; i++) {
            NSLog(@"t 1 : %d", i);
        }
        
    });
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"t 2: %@", [NSThread currentThread]);
        
        for (int i = 0; i < 20; i++) {
            NSLog(@"t 2 : %d", i);
        }
        
    });
    
    dispatch_group_notify(group, queue, ^{
       
        NSLog(@"finish : %@", [NSThread currentThread]);
        
    });
    
    
    dispatch_group_t group1 = dispatch_group_create();
    dispatch_queue_t queue1 = dispatch_queue_create("com.wxhl.c", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_group_async(group1, queue1, ^{
        
        NSLog(@"g 1: %@", [NSThread currentThread]);
        
        for (int i = 0; i < 100; i++) {
            NSLog(@"g 1 : %d", i);
        }
        
    });
    
    dispatch_group_notify(group1, queue1, ^{
       
        NSLog(@"finish");
    });
}

- (void)gcd2
{
    // 死锁问题
    
    // 串行队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 主队列
    dispatch_sync(queue, ^{
        NSLog(@"sync1 : %@", [NSThread currentThread]);
    });
}

- (void)gcd1
{
    /**
     *  (1) 队列的名字 "com.wxhl.q"
     *  (2) 队列的属性
            a. DISPATCH_QUEUE_CONCURRENT (并发队列(global_queue),并发线程队列)
            b. DISPATCH_QUEUE_SERIAL (串行队列 只会创建一个子线程,顺序执行(依赖))
            c. dispatch_get_main_queue 主队列
     *  (3) 是否开辟子线程,看对队列,和异步和同步无关,如果是主队列,在主线程中,其他队列都是创建了子线程
     */
    
    dispatch_queue_t queue = dispatch_queue_create("com.wxhl.q", DISPATCH_QUEUE_CONCURRENT);
    /**
     *  队列的优先级
     */
    //dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(queue, ^{
        
        NSLog(@"t 1 : %@", [NSThread currentThread]);
        for (int i = 0; i < 20; i++) {
            NSLog(@"t 1 : %d", i);
        }
        
        /*
         // 同步
         dispatch_sync(dispatch_get_main_queue(), ^{
         
         NSLog(@"%@", [NSThread currentThread]);
         });*/
        
        // 异步(请参考 waitUntilDone:YES理解)
        dispatch_async(dispatch_get_main_queue(), ^{
            
            //NSLog(@"%@", [NSThread currentThread]);
            
        });
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"t 2 : %@", [NSThread currentThread]);
        for (int i = 0; i < 20; i++) {
            NSLog(@"t 2 : %d", i);
        }
        
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"t 3 : %@", [NSThread currentThread]);
        for (int i = 0; i < 20; i++) {
            NSLog(@"t 3 : %d", i);
        }
        
    });
    
    //[NSThread detachNewThreadSelector:@selector(test1) toTarget:self withObject:nil];
}

- (void)test1
{
    // .....
    
    [self performSelectorOnMainThread:@selector(refreshUI) withObject:nil waitUntilDone:YES];
    
    // .....
}

- (void)refreshUI
{
    
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值