线程状态-互斥锁-通信

线程状态/互斥锁/通信

标签(空格分隔): 多线程


线程的5种状态

  • 新建、就绪、运行、阻塞、死亡
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    // 线程的新建
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];

    // 线程开始(start)
    [thread start];
    NSLog(@"开始执行子线程");
}

- (void)run{

    for (int i = 0 ; i< 50; i++) {

        NSLog(@"%d",i);

        if (i % 5 == 0) {
            // 让线程休息2秒(阻塞)
            [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
            NSLog(@"线程正在休息");

            if (i == 30) {
                // 结束线程(死亡)
                NSLog(@"子线程挂了");
                [NSThread exit];
                /*简单粗暴地结束方式:return;*/
            }
        }
    }
}

互斥锁/线程同步(@synchronized(对象))

  • 用途:为了解决一块资源被多个线程共享造成的数据紊乱数据安全问题

  • 只要被@synchronized的{}包裹起来的代码, 同一时刻就只能被一个线程执行

  • 注意:
    1. 只要枷锁就会消耗性能
    2. 加锁必须传递一个对象, 作为锁(一般都是传self)
    3. 如果想真正的锁住代码,那么多个线程必须使用同一把锁才行
    4. 加锁的时候尽量缩小范围, 因为范围越大性能就越低

原子和非原子属性

  • atomic:原子属性,为setter方法加锁(默认就是atomic)
  • nonatomic:非原子属性,不会为setter方法加锁

  • 对比

    • atomic:线程安全,需要消耗大量的资源
    • nonatomic:非线程安全,适合内存小的移动设备

注意点

  • atomic系统自动给我们添加的锁不是互斥锁(而是自旋锁)

  • 互斥锁和自旋锁共同点

    • 都能够保证多线程在同一时候,只能有一个线程操作锁定的代码
  • 互斥锁和自旋锁不同点
    • 如果是互斥锁,假如现在被锁住了,那么后面来得线程就会进入”休眠”状态, 直到解锁之后, 又会唤醒线程继续执行
    • 如果是自旋锁,假如现在被锁住了,那么后面来得线程不会进入休眠状态, 会一直傻傻的等待, 直到解锁之后立刻执行
    • 自旋锁更适合做一些较短的操作
  • 尽量避免多线程抢夺同一块资源,尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

线程间通信

  • 1个线程传递数据给另1个线程
  • 在1个线程中执行完特定任务后,转到另1个线程继续执行任务
  • 常用方法:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
// waitUntilDone的含义: 
    如果传入的是YES: 那么会等到主线程中的方法执行完毕, 才会继续执行下面其他行的代码
    如果传入的是NO: 那么不用等到主线程中的方法执行完毕, 就可以继续执行下面其他行的代码
  • 从子线程回到主线程(加入主队列)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 执行耗时的异步操作...
      dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程,执行UI刷新操作
        });
});
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    // 穿件队列,获取全局并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    // 添加下载任务到子线程中
    dispatch_async(queue, ^{

        NSLog(@"%@",[NSThread currentThread]);
        // 下载图片
        NSURL *url = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/1b4c510fd9f9d72aee889e1fd22a2834359bbbc0.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];

        UIImage *image = [UIImage imageWithData:data];

        // 显示UI控件,将此任务加入到主队列中

        // 如果是通过异步函数添加任务,会先执行完所有代码再来执行block中的任务
        // 如果是通过同步函数添加的任务,会先执行完block中的任务再执行其他代码
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"%@",[NSThread currentThread]);
            self.imageView.image = image;
        });

    });
}

你可能感兴趣的:(多线程)