NSThread 教程

1.NSThread的基本使用

ZYXThread.h

#import <Foundation/Foundation.h>

@interface ZYXThread : NSThread
@end

ZYXThread.m

#import "ZYXThread.h"

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

ViewController.h

#import <UIKit/UIKit.h>

@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{
    // 創(chuàng)建線程
    //NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
    // 啟動(dòng)線程
    //[thread start];
    
//創(chuàng)建的妖、啟動(dòng)線程 線程一啟動(dòng),就會(huì)在線程thread中執(zhí)行self的run方法
    ZYXThread *thread = [[ZYXThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
    thread.name = @"zyx-thread-1";//設(shè)置線程名字
    [thread start];//啟動(dòng)線程
}

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

一個(gè)NSThread對(duì)象就代表一條線程

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

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


// run2-----rose-----<NSThread: 0x7faae250e490>{number = 2, name = (null)}
// run2-----rose-----<NSThread: 0x7faae260cc50>{number = 3, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24a9d80>{number = 4, name = (null)}
// run2-----rose-----<NSThread: 0x7faae251f410>{number = 5, name = (null)}
// run2-----rose-----<NSThread: 0x7faae251f460>{number = 6, name = (null)}
// run2-----rose-----<NSThread: 0x7faae2511250>{number = 7, name = (null)}
// run2-----rose-----<NSThread: 0x7faae2511250>{number = 8, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24ab980>{number = 9, name = (null)}
// run2-----rose-----<NSThread: 0x7faae25112d0>{number = 10, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24b8e20>{number = 11, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24b7c40>{number = 12, name = (null)}
// run2-----rose-----<NSThread: 0x7faae251a8f0>{number = 13, name = (null)}

執(zhí)行完thread的任務(wù)并沒(méi)有銷毀這個(gè)thread

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

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

// run3-----bill-----<NSThread: 0x7fcd2bd1b920>{number = 2, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 3, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2be0c9e0>{number = 4, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 5, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2be0c9e0>{number = 6, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bc6fd90>{number = 7, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf0cba0>{number = 8, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bd155f0>{number = 9, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf0cba0>{number = 10, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bd155f0>{number = 11, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf037d0>{number = 12, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bd155f0>{number = 13, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2be15b30>{number = 14, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 15, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 16, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bc70320>{number = 17, name = (null)}

執(zhí)行完thread的任務(wù)并沒(méi)有銷毀這個(gè)thread

2.線程的狀態(tài)

- (void)run{
    for (NSInteger i = 0; i<10; i++) {
        NSLog(@"run-----%zd", i);
        if (i == 4) {
            [NSThread exit]; // 強(qiáng)制直接退出線程進(jìn)入死亡狀態(tài)(從內(nèi)存中銷毀)
        }
    }
}

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

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

注意:一旦線程停止(死亡)了孝宗,就不能再次開(kāi)啟任務(wù)

- (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

線程進(jìn)入阻塞狀態(tài)(離開(kāi)可調(diào)度線程池,線程沒(méi)有銷毀仍在內(nèi)存中)

3.線程安全

@interface ViewController ()
/** 售票員01 */
@property (nonatomic, strong) ZYXThread *thread01;
/** 售票員02 */
@property (nonatomic, strong) ZYXThread *thread02;
/** 售票員03 */
@property (nonatomic, strong) ZYXThread *thread03;
/** 票的總數(shù) */
@property (nonatomic, assign) NSInteger ticketCount;
@end

@implementation ViewController

- (void)saleTicket{
    while (1) {
        @synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
            NSInteger count = self.ticketCount;
            if (count > 0) {
                self.ticketCount = count - 1;
                NSLog(@" 線程 %@   賣了一張票尉辑,還剩下%zd張", [ZYXThread currentThread].name, self.ticketCount);
            } else {
                NSLog(@" 線程 %@   票已經(jīng)賣完了",[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   票已經(jīng)賣完了
//  線程 售票員03   票已經(jīng)賣完了
//  線程 售票員01   票已經(jīng)賣完了

@synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
互斥鎖保證線程安全

/** 鎖對(duì)象 */
@property (nonatomic, strong) NSObject *locker;

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

- (void)saleTicket{
    while (1) {
        //@synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
        @synchronized(self.locker){


//  線程 售票員01   賣了一張票革骨,還剩下9張
//  線程 售票員02   賣了一張票,還剩下8張
//  線程 售票員03   賣了一張票析恋,還剩下7張
//  線程 售票員01   賣了一張票良哲,還剩下6張
//  線程 售票員02   賣了一張票,還剩下5張
//  線程 售票員03   賣了一張票助隧,還剩下4張
//  線程 售票員01   賣了一張票筑凫,還剩下3張
//  線程 售票員02   賣了一張票,還剩下2張
//  線程 售票員03   賣了一張票并村,還剩下1張
//  線程 售票員01   賣了一張票巍实,還剩下0張
//  線程 售票員02   票已經(jīng)賣完了
//  線程 售票員03   票已經(jīng)賣完了
//  線程 售票員01   票已經(jīng)賣完了

使用同一把互斥鎖 保證線程安全

- (void)saleTicket{
    while (1) {
        //@synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
        //@synchronized(self.locker){
            NSInteger count = self.ticketCount;
            if (count > 0) {
                self.ticketCount = count - 1;
                NSLog(@" 線程 %@   賣了一張票,還剩下%zd張", [ZYXThread currentThread].name, self.ticketCount);
            } else {
                NSLog(@" 線程 %@   票已經(jīng)賣完了",[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   票已經(jīng)賣完了
//  線程 售票員03   票已經(jīng)賣完了
//  線程 售票員01   票已經(jīng)賣完了

不使用線程同步技術(shù) 不使用互斥鎖 數(shù)據(jù)錯(cuò)亂

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]; // 根據(jù)圖片的網(wǎng)絡(luò)路徑去下載圖片數(shù)據(jù)
    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();

(錯(cuò)誤方式)在子線程顯示圖片

- (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];
}

子線程和主線程的數(shù)據(jù)通信:
子線程下載圖片 把下載好的圖片 傳到主線程顯示在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;
        });
    });
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘱吗,一起剝皮案震驚了整個(gè)濱河市玄组,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谒麦,老刑警劉巖俄讹,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異绕德,居然都是意外死亡患膛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門耻蛇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)踪蹬,“玉大人,你說(shuō)我怎么就攤上這事臣咖≡镜罚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵夺蛇,是天一觀的道長(zhǎng)疚漆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)刁赦,這世上最難降的妖魔是什么娶聘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮甚脉,結(jié)果婚禮上丸升,老公的妹妹穿的比我還像新娘。我一直安慰自己宦焦,他們只是感情好发钝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著波闹,像睡著了一般酝豪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上精堕,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天孵淘,我揣著相機(jī)與錄音,去河邊找鬼歹篓。 笑死瘫证,一個(gè)胖子當(dāng)著我的面吹牛揉阎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播背捌,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼毙籽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了毡庆?” 一聲冷哼從身側(cè)響起坑赡,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎么抗,沒(méi)想到半個(gè)月后毅否,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝇刀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年螟加,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吞琐。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捆探,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出顽分,到底是詐尸還是另有隱情徐许,我是刑警寧澤施蜜,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布卒蘸,位于F島的核電站,受9級(jí)特大地震影響翻默,放射性物質(zhì)發(fā)生泄漏缸沃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一修械、第九天 我趴在偏房一處隱蔽的房頂上張望趾牧。 院中可真熱鬧,春花似錦肯污、人聲如沸翘单。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哄芜。三九已至,卻和暖如春柬唯,著一層夾襖步出監(jiān)牢的瞬間认臊,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工锄奢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留失晴,地道東北人剧腻。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像涂屁,于是被迫代替她去往敵國(guó)和親书在。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 本文選譯自《Threading Programming Guide》拆又。 導(dǎo)語(yǔ) 線程技術(shù)作為在單個(gè)應(yīng)用程序中并發(fā)執(zhí)行...
    巧巧的二表哥閱讀 2,437評(píng)論 4 24
  • .一.進(jìn)程 進(jìn)程:是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,每個(gè)進(jìn)程之間是獨(dú)立的蕊温,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空...
    IIronMan閱讀 4,486評(píng)論 1 33
  • NSThread 第一種:通過(guò)NSThread的對(duì)象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 799評(píng)論 0 3
  • 一提到曼谷义矛,首先會(huì)想到就兩個(gè)字,享樂(lè)盟萨! 可以去王權(quán)免稅店買買買凉翻,可以去高空酒吧,夜場(chǎng)party嗨嗨嗨捻激,可以深入到市...
    走啦旅行閱讀 545評(píng)論 0 5
  • 文/魯陽(yáng)浩 我的天空 總有這么灰 我的天空 總有淚水 沒(méi)有星空的夜晚 我走在空曠的街道 聞著舊燈光的味道 尋找前行...
    靜候天時(shí)閱讀 508評(píng)論 1 1