多线程卖票之-NSThread、NSOperation、GCD


要售票首先要找一个变量来存放票数,但是直接放在一个变量里面改来改去的不方便,所以用一个NSObject对象的成员变量来存储。

Ticket.h:

</pre><pre name="code" class="cpp" style="color: rgb(255, 0, 0);">#import <Foundation/Foundation.h>

@interface Ticket : NSObject

+(Ticket *)sharedTicket;
//票数
@property (assign, atomic) NSInteger tickets;

@end

Ticket.m:

</pre><span style="font-size:14px;color:#ff0000;"></span><pre name="code" class="cpp" style="color: rgb(255, 0, 0);">#import "Ticket.h"

static Ticket *SharedInstance;
/*
 做单例模型:
 1、用静态变量来储存第一个被实例化的对象
 2、重写allocWithZone方法,并使用diapatch_once_t
 3、建立一个
 */
@implementation Ticket
//要实例化出来唯一的对象,要记录第一个实例化出来的对象
//只能在单线程中,如果用两个线程来跑,会出现两个
+ (id)allocWithZone:(struct _NSZone *)zone
{
    //解决多线程问题,只能实例化一个对象副本
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SharedInstance = [super allocWithZone:zone];
    });
//    
//    if (SharedInstance == nil) {
//        SharedInstance = [super allocWithZone:zone];
//    }
    return SharedInstance;
}
//建立一个单例对象,便于调用
+(Ticket *)sharedTicket
{
    //块代码里面只能使用外面的对象,不能修改外面的对象,要修改必须要加__block
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SharedInstance = [[Ticket alloc]init];
    });

    return SharedInstance;
}
@end

然后在MainViewController里面定义线程对票数进行操作:

MainViewController.h:

#import <UIKit/UIKit.h>

@interface MainViewController : UIViewController

@end
MainViewController.m:

#import "MainViewController.h"
#import "Ticket.h"
@interface MainViewController ()
@property (weak, nonatomic) UITextView *textView;
@property (strong, nonatomic) NSOperationQueue *queue;
@end

@implementation MainViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}
#pragma mark - 追加当前文本框内容
- (void)appendContent:(NSString *)text
{
    //1、取出textView内容
    NSMutableString *str = [NSMutableString stringWithString:self.textView.text];
    //2、将text追加至TextView内容的末尾
    [str appendFormat:@"%@\n",text];
    //3、使用追加后的文本,替换textView中的内容
    [self.textView setText:str];
    //4、将textView滚动至底部
    NSRange range = NSMakeRange(str.length - 1, 1);
    [self.textView scrollRangeToVisible:range];

}
- (void)viewDidLoad
{
    [super viewDidLoad];
//    Ticket *ticket1 = [[Ticket alloc]init];
//    ticket1.tickets = 100;
//    NSLog(@"%@",ticket1);
//    Ticket *ticket2 = [[Ticket alloc]init];//alloc是分配空间,init是初始化属性
//    NSLog(@"%d - %@",ticket2.tickets,ticket2);
//    NSLog(@"%@",[Ticket sharedTicket]);
    //使用内存地址实例化方法,所有实例化方法,最终都会调用此方法;
//    [Ticket allocWithZone:<#(struct _NSZone *)#>]
    UITextView *textView = [[UITextView alloc]initWithFrame:self.view.bounds];
    [textView setEditable:NO];
    [textView setText:@""];
    [self.view addSubview:textView];
    self.textView = textView;
   
    [Ticket sharedTicket].tickets = 30;
    NSInteger num = [Ticket sharedTicket].tickets;
    
//    [self gcdSales];
    self.queue = [[NSOperationQueue alloc]init];
//    [self operationSales];
    [self threadSales];
}


#pragma mark - NSThread卖票
- (void)threadSaleTicketWithName:(NSString *)name
{
    //使用NSThread一定要用autoreleasepool包起来
    //因为main.m里面的@autoreleasepool只处理主线程内存问题
    //线程很多时,处理数据量很大时,很容易出问题
    @autoreleasepool {
        while (YES) {
            @synchronized(self){
                if ([Ticket sharedTicket].tickets > 0) {
                    [Ticket sharedTicket].tickets--;
                    NSString *str = [NSString stringWithFormat:@"剩余票数%d 线程名称%@",[Ticket sharedTicket].tickets,name];
                    //更新UI
                    [self performSelectorOnMainThread:@selector(appendContent:) withObject:str waitUntilDone:YES];
                }else{
                    NSLog(@"票卖完了%@ %@",name,[NSThread currentThread]);
                    break;
                }
            }
            if ([name isEqualToString:@"thread-1"]) {
                [NSThread sleepForTimeInterval:1.0f];
            }else{
                [NSThread sleepForTimeInterval:0.2f];
            }
        }
    }
}
- (void)threadSales
{
    [NSThread detachNewThreadSelector:@selector(threadSaleTicketWithName:) toTarget:self withObject:@"thread-1"];
    
    [NSThread detachNewThreadSelector:@selector(threadSaleTicketWithName:) toTarget:self withObject:@"thread-2"];
}
#pragma mark - NSOperation卖票
- (void)operationSaleTicketWithName:(NSString *)name
{
    while (YES) {
        @synchronized(self){
            if ([Ticket sharedTicket].tickets > 0) {
                [Ticket sharedTicket].tickets--;
                NSString *str = [NSString stringWithFormat:@"剩余票数%d,线程名%@",[Ticket sharedTicket].tickets,name];
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    [self appendContent:str];
                }];
            }else {
                NSLog(@"票卖完了%@ %@",name,[NSThread currentThread]);
                break;
            }
        }
        if ([name isEqualToString:@"op-1"]) {
            [NSThread sleepForTimeInterval:1.0f];
        }else{
            [NSThread sleepForTimeInterval:0.2f];
        }
    }
}
- (void)operationSales
{
    //没有任务完成提示的功能
    [self.queue setMaxConcurrentOperationCount:2];
    [self.queue addOperationWithBlock:^{
        [self operationSaleTicketWithName:@"op-3"];
    }];
    [self.queue addOperationWithBlock:^{
        [self operationSaleTicketWithName:@"op-1"];
    }];
    //op-2被同步锁挡在外面了
    [self.queue addOperationWithBlock:^{
        [self operationSaleTicketWithName:@"op-2"];
    }];

}
#pragma mark - GCD 买票
- (void)gcdSaleTicketWithName:(NSString *)name
{
    while (YES) {
        
        @synchronized(self) {
            if ([Ticket sharedTicket].tickets > 0) {
                
                [Ticket sharedTicket].tickets--;
                
                // 提示内容
                NSString *str = [NSString stringWithFormat:@"剩余票数 %d, 线程名称 %@", [Ticket sharedTicket].tickets, name];
                
                // 更新界面
                dispatch_sync(dispatch_get_main_queue(), ^{
                    [self appendContent:str];
                });
            } else {

                break;
            }
            
        }
        
        // 模拟线程休眠
        if ([name isEqualToString:@"gcd-1"]) {
            [NSThread sleepForTimeInterval:1.0f];
        } else {
            [NSThread sleepForTimeInterval:0.2f];
        }
    }
}
- (void)gcdSales
{
    //1、创建全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //创建两个线程分别卖票
//    dispatch_async(queue, ^{
//        [self gcdSaleTicketWithName:@"gcd-1"];
//    });
//    dispatch_async(queue, ^{
//        [self gcdSaleTicketWithName:@"gcd-2"];
//    });
//    dispatch_async(queue, ^{
//        [self gcdSaleTicketWithName:@"gcd-3"];
//    });
    //GCD中可以将一组相关联的操作,定义到一个群组中
    //定义到群组中的操作可以当所有线程全部完成之后获得通知
    //最典型的应用是小说阅读时候,所有的书下载完毕之后提醒用户下载
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        [self gcdSaleTicketWithName:@"gcd-1"];
    });
    dispatch_group_async(group, queue, ^{
        [self gcdSaleTicketWithName:@"gcd-2"];
    });
    dispatch_group_async(group, queue, ^{
        [self gcdSaleTicketWithName:@"gcd-3"];
    });
    //等的时间长的执行次数少,等待时间短的执行次数多
    //群组任务完成接收通知
    dispatch_group_notify(group, queue, ^{
        NSLog(@"卖完了所有的票");
    });
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值