NSThread 教程

1.NSThread的基本使用

ZYXThread.h

#import 

@interface ZYXThread : NSThread
@end

ZYXThread.m

#import "ZYXThread.h"

@implementation ZYXThread
- (void)dealloc
{
    NSLog(@"ZYXThread -- dealloc");
}
@end

ViewController.h

#import 

@interface ViewController : UIViewController
@end

ViewController.m

#import "ViewController.h"

#import "ZYXThread.h"

@implementation ViewController

- (void)run:(NSString *)param{
    for (NSInteger i = 0; i<3; i++) {
        NSLog(@"run-----%@-----%@", param, [NSThread currentThread]);
    }
}

- (void)createThread1{
    // 创建线程
    //NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
    // 启动线程
    //[thread start];
    
//创建、启动线程 线程一启动,就会在线程thread中执行self的run方法
    ZYXThread *thread = [[ZYXThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
    thread.name = @"zyx-thread-1";//设置线程名字
    [thread start];//启动线程
}

// run-----jack-----{number = 2, name = zyx-thread-1}
// run-----jack-----{number = 2, name = zyx-thread-1}
// run-----jack-----{number = 2, name = zyx-thread-1}
//2016-08-09 11:09:10.659 NSThread[25371:417117] ZYXThread -- dealloc
@end

一个NSThread对象就代表一条线程

- (void)run2:(NSString *)param{
    NSLog(@"run2-----%@-----%@", param, [NSThread currentThread]);
}

- (void)createThread2{
    //detach 分离
    [ZYXThread detachNewThreadSelector:@selector(run2:) toTarget:self withObject:@"rose"];
}


// run2-----rose-----{number = 2, name = (null)}
// run2-----rose-----{number = 3, name = (null)}
// run2-----rose-----{number = 4, name = (null)}
// run2-----rose-----{number = 5, name = (null)}
// run2-----rose-----{number = 6, name = (null)}
// run2-----rose-----{number = 7, name = (null)}
// run2-----rose-----{number = 8, name = (null)}
// run2-----rose-----{number = 9, name = (null)}
// run2-----rose-----{number = 10, name = (null)}
// run2-----rose-----{number = 11, name = (null)}
// run2-----rose-----{number = 12, name = (null)}
// run2-----rose-----{number = 13, name = (null)}

执行完thread的任务并没有销毁这个thread

- (void)run3:(NSString *)param{
    NSLog(@"run3-----%@-----%@", param, [NSThread currentThread]);
}

- (void)createThread3{
    [self performSelectorInBackground:@selector(run3:) withObject:@"bill"];
}

// run3-----bill-----{number = 2, name = (null)}
// run3-----bill-----{number = 3, name = (null)}
// run3-----bill-----{number = 4, name = (null)}
// run3-----bill-----{number = 5, name = (null)}
// run3-----bill-----{number = 6, name = (null)}
// run3-----bill-----{number = 7, name = (null)}
// run3-----bill-----{number = 8, name = (null)}
// run3-----bill-----{number = 9, name = (null)}
// run3-----bill-----{number = 10, name = (null)}
// run3-----bill-----{number = 11, name = (null)}
// run3-----bill-----{number = 12, name = (null)}
// run3-----bill-----{number = 13, name = (null)}
// run3-----bill-----{number = 14, name = (null)}
// run3-----bill-----{number = 15, name = (null)}
// run3-----bill-----{number = 16, name = (null)}
// run3-----bill-----{number = 17, name = (null)}

执行完thread的任务并没有销毁这个thread

2.线程的状态

- (void)run{
    for (NSInteger i = 0; i<10; i++) {
        NSLog(@"run-----%zd", i);
        if (i == 4) {
            [NSThread exit]; // 强制直接退出线程进入死亡状态(从内存中销毁)
        }
    }
}

- (void)createThread {
    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}

// run-----0
// run-----1
// run-----2
// run-----3
// run-----4

注意:一旦线程停止(死亡)了,就不能再次开启任务

- (void)run2{
    NSLog(@"%@",[NSDate date]);
    // 阻塞(暂停)线程
    [NSThread sleepForTimeInterval:2]; // 让线程睡眠2秒(阻塞2秒)
    NSLog(@"%@",[NSDate date]);
    //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
    //[NSThread sleepUntilDate:[NSDate distantFuture]];
}

// 2016-08-09 05:36:01 +0000
// 2016-08-09 05:36:03 +0000

线程进入阻塞状态(离开可调度线程池,线程没有销毁仍在内存中)

3.线程安全

@interface ViewController ()
/** 售票员01 */
@property (nonatomic, strong) ZYXThread *thread01;
/** 售票员02 */
@property (nonatomic, strong) ZYXThread *thread02;
/** 售票员03 */
@property (nonatomic, strong) ZYXThread *thread03;
/** 票的总数 */
@property (nonatomic, assign) NSInteger ticketCount;
@end

@implementation ViewController

- (void)saleTicket{
    while (1) {
        @synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
            NSInteger count = self.ticketCount;
            if (count > 0) {
                self.ticketCount = count - 1;
                NSLog(@" 线程 %@   卖了一张票,还剩下%zd张", [ZYXThread currentThread].name, self.ticketCount);
            } else {
                NSLog(@" 线程 %@   票已经卖完了",[ZYXThread currentThread].name);
                break;
            }
        }
    }
}

- (void)start{
    self.ticketCount = 10;
    
    self.thread01 = [[ZYXThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread01.name = @"售票员01";
    
    self.thread02 = [[ZYXThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread02.name = @"售票员02";
    
    self.thread03 = [[ZYXThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread03.name = @"售票员03";
    [self.thread01 start];
    [self.thread02 start];
    [self.thread03 start];
}

@end 

//  线程 售票员01   卖了一张票,还剩下9张
//  线程 售票员02   卖了一张票,还剩下8张
//  线程 售票员03   卖了一张票,还剩下7张
//  线程 售票员01   卖了一张票,还剩下6张
//  线程 售票员02   卖了一张票,还剩下5张
//  线程 售票员03   卖了一张票,还剩下4张
//  线程 售票员01   卖了一张票,还剩下3张
//  线程 售票员02   卖了一张票,还剩下2张
//  线程 售票员03   卖了一张票,还剩下1张
//  线程 售票员01   卖了一张票,还剩下0张
//  线程 售票员02   票已经卖完了
//  线程 售票员03   票已经卖完了
//  线程 售票员01   票已经卖完了

@synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
互斥锁保证线程安全

/** 锁对象 */
@property (nonatomic, strong) NSObject *locker;

- (void)start{
    self.locker = [[NSObject alloc] init];

- (void)saleTicket{
    while (1) {
        //@synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
        @synchronized(self.locker){


//  线程 售票员01   卖了一张票,还剩下9张
//  线程 售票员02   卖了一张票,还剩下8张
//  线程 售票员03   卖了一张票,还剩下7张
//  线程 售票员01   卖了一张票,还剩下6张
//  线程 售票员02   卖了一张票,还剩下5张
//  线程 售票员03   卖了一张票,还剩下4张
//  线程 售票员01   卖了一张票,还剩下3张
//  线程 售票员02   卖了一张票,还剩下2张
//  线程 售票员03   卖了一张票,还剩下1张
//  线程 售票员01   卖了一张票,还剩下0张
//  线程 售票员02   票已经卖完了
//  线程 售票员03   票已经卖完了
//  线程 售票员01   票已经卖完了

使用同一把互斥锁 保证线程安全

- (void)saleTicket{
    while (1) {
        //@synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
        //@synchronized(self.locker){
            NSInteger count = self.ticketCount;
            if (count > 0) {
                self.ticketCount = count - 1;
                NSLog(@" 线程 %@   卖了一张票,还剩下%zd张", [ZYXThread currentThread].name, self.ticketCount);
            } else {
                NSLog(@" 线程 %@   票已经卖完了",[ZYXThread currentThread].name);
                break;
            }
        //}
    }
}


//  线程 售票员01   卖了一张票,还剩下8张
//  线程 售票员02   卖了一张票,还剩下8张
//  线程 售票员03   卖了一张票,还剩下7张
//  线程 售票员01   卖了一张票,还剩下6张
//  线程 售票员02   卖了一张票,还剩下5张
//  线程 售票员03   卖了一张票,还剩下4张
//  线程 售票员01   卖了一张票,还剩下3张
//  线程 售票员02   卖了一张票,还剩下2张
//  线程 售票员03   卖了一张票,还剩下1张
//  线程 售票员01   卖了一张票,还剩下0张
//  线程 售票员02   票已经卖完了
//  线程 售票员03   票已经卖完了
//  线程 售票员01   票已经卖完了

不使用线程同步技术 不使用互斥锁 数据错乱

4.线程间通信

@property (weak, nonatomic) IBOutlet UIImageView *imageView;
- (void)download{
    NSString *imgUrlStr = @"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg";
    NSURL *url = [NSURL URLWithString:imgUrlStr];
    
    NSDate *begin = [NSDate date];
    NSData *data = [NSData dataWithContentsOfURL:url]; // 根据图片的网络路径去下载图片数据
    NSDate *end = [NSDate date];
    NSLog(@"%f", [end timeIntervalSinceDate:begin]);
    
    self.imageView.image = [UIImage imageWithData:data];
}

- (void)way{
    [self performSelectorInBackground:@selector(download) withObject:nil];
}

// 3.728395

CFTimeInterval begin = CFAbsoluteTimeGetCurrent();
NSData *data = [NSData dataWithContentsOfURL:url];
CFTimeInterval end = CFAbsoluteTimeGetCurrent();

(错误方式)在子线程显示图片

- (void)download3{
    NSString *imgUrlStr = @"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg";
    NSURL *url = [NSURL URLWithString:imgUrlStr];
    NSData *data = [NSData dataWithContentsOfURL:url];
    
    UIImage *image = [UIImage imageWithData:data]; // 生成图片
    
    // 回到主线程 显示图片
    /*
    [self.imageView performSelector:@selector(setImage:)
                           onThread:[NSThread mainThread]
                         withObject:image
                      waitUntilDone:NO];
    
    [self.imageView performSelectorOnMainThread:@selector(setImage:)
                                     withObject:image
                                  waitUntilDone:NO];
    */
    [self performSelectorOnMainThread:@selector(showImage:)
                           withObject:image
                        waitUntilDone:YES];
}

- (void)showImage:(UIImage *)image{
    self.imageView.image = image;
}

- (void)way3{
    [self performSelectorInBackground:@selector(download3) withObject:nil];
}

子线程和主线程的数据通信:
子线程下载图片 把下载好的图片 传到主线程显示在imageView上

另外一种线程之间的通信方式

NSPort
NSMessagePort
NSMachPort

5.GCD线程间通信

- (void)loadImage {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSString *imgUrlStr = @"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg";
        NSURL *url = [NSURL URLWithString:imgUrlStr];
        
        NSData *data = [NSData dataWithContentsOfURL:url]; // 加载图片
        UIImage *image = [UIImage imageWithData:data]; // 生成图片
        
        // 回到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = image;
        });
    });
}

你可能感兴趣的:(NSThread 教程)