iOS多线程之NSThread

来源:互联网 发布:linux是什么意思啊 编辑:程序博客网 时间:2024/05/04 22:39

以前对多线程总是有点陌生感,虽然平时也一样在用,但总是感觉不够亲密。这两天就彻底整理一下,但是由于是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
1 0
原创粉丝点击