【iOS进阶】【多线程】4-资源共享

一、多线程中的资源共享

1>并发编程中许多问题的根源就是在多线程中访问共享资源。资源可以是一个属性、一个对象、网络设备或者一个文件等

2>在多线程中任何一个共享的资源都可能是一个潜在的冲突点,必须精心设计以防止这种冲突的发生

3>资源共享导致的资源抢夺示意图

  

4>加入互斥锁(@synchronized),避免资源抢夺

    

5>共享资源小结

  1.为了保证性能,atomic仅针对属性的setter方法做了保护

  2.而争抢共享资源时,如果涉及到属性的getter方法,可以使用互斥锁@synchronized可以保证属性在多个线程之间的读写都是安全的

  3.无论是atomic还是@synchronized,使用的代价都是高昂的

  4.建议:多线程是并发执行多个任务提高效率的,如果可能,应该在线程中避免争抢共享资源

  正是出于性能的考虑,UIKit中的绝大多数的类都不是线程安全的,因此,苹果公司要求:更新UI相关的操作,应该在主线程中执行

一、资源抢夺示例

1>系统预设共

  1.有N张票可以销售

  2.售票工作由多个线程并发进行

  3.没有可出售票据时,线程工作停止

  4.子线程的执行效率不同,模拟售票人员效率不同

  5.使用一个多行文本框公告售票进度(主线程更新UI)

  6.线程工作安排

    主线程:负责更新UI

    多个子线程:模拟多名卖票员

2>单线程卖票流程图

    

3>多线程卖票示意图

    

4>示例代码

#import "ViewController.h"

@interface ViewController ()

/**
 *  票数
 
 如果只是开发单写多读的功能,只需要使用原子锁即可(把nonatomic改成atomic)
 
 @synchronized 互斥锁消耗巨大,苹果官方不建议使用。
 
 在实际开发中,尽量不要去抢夺资源!抢夺资源的功能开发属于服务器的范畴
 
 并发编程最主要的目的事提高性能,让更多的代码同时进行。
 */
@property (atomic,assign) NSInteger tickets;

@property (weak, nonatomic) IBOutlet UITextView *textView;

- (IBAction)doSale:(id)sender;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark - 卖票操作
/**
 *  卖票循环,一直卖完为止
 */
-(void)doSaleLoop:(NSString *)opName{
    //所有线程进入都可以卖票
    while (YES) {
        //加互斥锁,在共享资源的“读“、“写”范围添加互斥锁
        //锁的范围要尽可能小
        //防止资源抢夺最简单的做法就是使用互斥锁@synchronized
        //使用互斥锁,会变慢,互斥锁的代价非常高昂
        //@synchronized(self){
        //}
        
        //是否有票
        if (self.tickets > 0){
            --self.tickets;
            NSLog(@"剩余票数:%ld - 卖票人:%@ -%@",(long)self.tickets,opName,[NSThread currentThread]);
        } else {
            NSLog(@"票已卖完");
            break;
        }
        
        //模拟休眠
        if ([opName isEqualToString:@"OP 1"]){
            [NSThread sleepForTimeInterval:0.1f];
        } else {
            [NSThread sleepForTimeInterval:0.2f];
            
        }
    }
}

#pragma mark - 模拟多人卖票

#pragma mark GCD实现
/**
 *  抢票按钮
 */
-(IBAction)doSale:(id)sender{
    //做多线程开发时,永远不要相信一次运行的结果
    self.tickets = 20;
    
    //1.队列。多人卖票应用并行队列,concurrent
    dispatch_queue_t q = dispatch_queue_create("sale", DISPATCH_QUEUE_CONCURRENT);
    //2.添加任务。抢票是异步的
    //2.1 第一个售票员
    dispatch_async(q, ^{
        [self doSaleLoop:@"OP 1"];
    });
    //2.2 第二个售票员
    dispatch_async(q, ^{
        [self doSaleLoop:@"OP 2"];
    });
    //2.3 第三个售票员
    dispatch_async(q, ^{
        [self doSaleLoop:@"OP 3"];
    });
    //2.4 第四个售票员
    dispatch_async(q, ^{
        [self doSaleLoop:@"OP 4"];
    });
}

@end

 

posted @ 2015-04-21 21:00  锟斤拷Dy  阅读(145)  评论(0)    收藏  举报