iOS多线程之NSThread

以前对多线程总是有点陌生感,虽然平时也一样在用,但总是感觉不够亲密。这两天就彻底整理一下,但是由于是demo代码那种,所以在这里我就不再重复敲字了,直接上代码吧。

//
//  JSC_NSThread.m
//  ios多线程学习
//
//  Created by huasu on 17/2/28.
//  Copyright © 2017年 JY. All rights reserved.
//

//NSThread实现的技术有下面三种:cocoa thread , POSIX threads  ,Multiprocessing Services 一般使用的是cocoa thread 技术
/*
 NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程)
 –优点:NSThread 比其他两个轻量级,使用简单
 –缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销

 */


#import "JSC_NSThread.h"

@interface JSC_NSThread ()
#define kURL @"http://s10.sinaimg.cn/mw690/56279263h7bdc5a0791f9&690.png"
@property (nonatomic,weak)UIImageView *imageview;
@property (nonatomic,strong)NSThread *thread;
@end

@implementation JSC_NSThread

-(void)learn
{
    //NSThread有两种直接创建方式:
    //1> 类方法直接开启后台线程,并执行选择器方法 detachNewThreadSelector
    // 新建一个线程,调用@selector方法
    [NSThread detachNewThreadSelector:@selector(bigDemo:) toTarget:self withObject:nil];
    //2> 成员方法,在实例化线程对象之后,需要使用start执行选择器方法  initWithTarget
    // 成员方法
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(bigDemo:) object:nil];
    // 启动start线程
    [thread start];
    //    参数:
    //    selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
    //    target  :selector消息发送的对象
    //    argument:传输给target的唯一参数,也可以是nil,即object后面的参数


    //    不显式创建线程的方法
    //    用NSObject的类方法  performSelectorInBackground:withObject: 创建一个线程:
    //对于NSThread的简单使用,可以用NSObject的performSelectorInBackground替代
    // performSelectorInBackground是将bigDemo的任务放在后台线程中执行
    [self performSelectorInBackground:@selector(bigDemo) withObject:nil];

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

    UIImageView *imageview=[[UIImageView alloc]init];
    self.imageview=imageview;
    imageview.frame=CGRectMake(10, 100, 200, 200);
    [self.view addSubview:imageview];

    UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame=CGRectMake(50, 400, 220, 25);
    [button setTitle:@"加载图片" forState:UIControlStateNormal];
    //添加方法
    [button addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];


    //如果网络不好,我们需要停止线程
    UIButton *btn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
    btn.frame=CGRectMake(50, 500, 220, 25);
    [btn setTitle:@"停止加载" forState:UIControlStateNormal];
    //停止线程
    [btn addTarget:self action:@selector(stopLoadImage) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];


}
-(void)stopLoadImage
{
        //判断线程是否完成,如果没有完成则设置为取消状态
        //注意设置为取消状态仅仅是改变了线程状态而言,并不能终止线程
        if (!self.thread.isFinished) {
            [self.thread cancel];

        }
}
-(void)loadImageWithMultiThread
{
    //这样我们点击button时会创建一个子线程去执行任务,这样加载图片的时候我们主线程的ui就不会卡死
     //如果多个线程加载图片,线程优先级范围为0~1,值越大优先级越高,每个线程的优先级默认为0.5 优先级越大的会越先执行,但未必第一个加载,首先代码中线程的启动顺序不一定,还有就是网络问题我们没法控制,每个线程执行时实际网络状况很可能不一致

    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
    self.thread=thread;
    [thread start];
}
-(void)updateUI:(UIImage*) image{
    self.imageview.image = image;
}

-(void)downloadImage:(NSString *) url{
    NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
    UIImage *image = [[UIImage alloc]initWithData:data];
    if(image == nil){

    }else{
        [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

说到多线程了,肯定少不了的就是线程锁了,下面附一个经典的卖票例子吧

//
//  JSC_ticket.m
//  ios多线程学习
//
//  Created by huasu on 17/3/1.
//  Copyright © 2017年 JY. All rights reserved.
//

#import "JSC_ticket.h"

@interface JSC_ticket ()
{
    int sum;//原始总票数
    int tickets;//当前票数
    int count;//售出票数
    NSThread* ticketsThreadone;
    NSThread* ticketsThreadtwo;
    NSCondition* ticketsCondition;//线程锁
    NSLock *theLock;//线程锁
}
@end

@implementation JSC_ticket

- (void)viewDidLoad {
    [super viewDidLoad];

    //线程同步
    [self text1];


//    //线程的顺序执行   他们都可以通过[ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。
//    [self text2];


//    其他同步
//    我们可以使用指令 @synchronized 来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。
//    - (void)doSomeThing:(id)anObj
//    {
//        @synchronized(anObj)
//        {
//            // Everything between the braces is protected by the @synchronized directive.
//        } 
//    }
//    还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习


}
-(void)text1
{
    sum =100;
    tickets = 100;
    count = 0;
    theLock = [[NSLock alloc] init];
    // 锁对象
    ticketsCondition = [[NSCondition alloc] init];
    ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run1) object:nil];
    [ticketsThreadone setName:@"Thread-1"];
    [ticketsThreadone start];

    ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run1) object:nil];
    [ticketsThreadtwo setName:@"Thread-2"];
    [ticketsThreadtwo start];
}
-(void)text2
{
    sum =100;
    tickets = 100;
    count = 0;
    theLock = [[NSLock alloc] init];
    // 锁对象
    ticketsCondition = [[NSCondition alloc] init];
    ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run2) object:nil];
    [ticketsThreadone setName:@"Thread-1"];
    [ticketsThreadone start];

    ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run2) object:nil];
    [ticketsThreadtwo setName:@"Thread-2"];
    [ticketsThreadtwo start];

    NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];
    [ticketsThreadthree setName:@"Thread-3"];
    [ticketsThreadthree start];

}
- (void)run1{
    while (TRUE) {

        // 上锁
        //        [ticketsCondition lock];
        [theLock lock];
        if(tickets >= 0){
            [NSThread sleepForTimeInterval:0.09];
            count = sum - tickets;
            NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
            tickets--;
        }else{
            break;//退出while死循环
        }
        [theLock unlock];
        //        [ticketsCondition unlock];
    }
    //如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
    //上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了。
}

- (void)run2{
    while (TRUE) {
        // 上锁
        [ticketsCondition lock];
        [ticketsCondition wait];
        [theLock lock];
        if(tickets >= 0){
            [NSThread sleepForTimeInterval:0.09];
            count = 100 - tickets;
            NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
            tickets--;
        }else{
            break;
        }
        [theLock unlock];
        [ticketsCondition unlock];
    }
}

-(void)run3{
    while (YES) {
        [ticketsCondition lock];
        [NSThread sleepForTimeInterval:3];
        [ticketsCondition signal];
        [ticketsCondition unlock];
    }
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值