iOS NSThread

1、知識(shí)梳理

  • 一個(gè)NSThread對(duì)象就代表一條線程
//  獲得當(dāng)前線程
NSThread*current = [NSThreadcurrentThread];

//  線程的名字
-(void)setName:(NSString*)n;
-(NSString*)name;

創(chuàng)建和啟動(dòng)線程

  • 該方式,需要手動(dòng)開啟線程
NSThread*thread = [[NSThre adalloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
//線程一啟動(dòng),就會(huì)在線程thread中執(zhí)行self的run方法
  • 其他創(chuàng)建線程方式:會(huì)自動(dòng)開啟線程
    • 優(yōu)點(diǎn):簡(jiǎn)單快捷
    • 缺點(diǎn):無法對(duì)線程進(jìn)行更詳細(xì)的設(shè)置:如,設(shè)置線程名稱等
// 創(chuàng)建線程后自動(dòng)啟動(dòng)線程
[NSThreaddetachNewThreadSelector:@selector(run)toTarget:selfwithObject:nil];

// 隱式創(chuàng)建并啟動(dòng)線程
[selfperformSelectorInBackground:@selector(run)withObject:nil];

主線程相關(guān)用法

+(NSThread*)mainThread;// 獲得主線程
-(BOOL)isMainThread;// 是否為主線程
+(BOOL)isMainThread;// 是否為主線程

線程狀態(tài)

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

    Snip20151030_17.png

  • 控制線程狀態(tài)方法:

// 啟動(dòng)線程
-(void)start;
//進(jìn)入就緒狀態(tài)->運(yùn)行狀態(tài)。當(dāng)線程任務(wù)執(zhí)行完畢,自動(dòng)進(jìn)入死亡狀態(tài)

 // 阻塞(暫停)線程
+(void)sleepUntilDate:(NSDate*)date;
+(void)sleepForTimeInterval:(NSTimeInterval)ti;
//進(jìn)入阻塞狀態(tài)

// 強(qiáng)制停止線程
+(void)exit;
//進(jìn)入死亡狀態(tài)

多線程的安全隱患 :

  • 資源共享

    • 1塊資源可能會(huì)被多個(gè)線程共享,也就是多個(gè)線程可能會(huì)訪問同一塊資源
    • 比如多個(gè)線程訪問同一個(gè)對(duì)象、同一個(gè)變量、同一個(gè)文件
  • 當(dāng)多個(gè)線程訪問同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問題

安全隱患解決– 互斥鎖

  • 互斥鎖使用格式

// 注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的
@synchronized(鎖對(duì)象){ //需要鎖定的代碼 }

+ 互斥鎖的優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題
- 缺點(diǎn):需要消耗大量的CPU資源

+ 互斥鎖的使用前提:
 - 多條線程搶奪同一塊資源

+ 線程同步: 多條線程在同一條線上執(zhí)行(按順序地執(zhí)行任務(wù))
 - 互斥鎖,就是使用了線程同步技術(shù)

> 線程間通信

+ 線程間通信的體現(xiàn)
 - 1個(gè)線程傳遞數(shù)據(jù)給另1個(gè)線程
 -  在1個(gè)線程中執(zhí)行完特定任務(wù)后,轉(zhuǎn)到另1個(gè)線程繼續(xù)執(zhí)行任務(wù)

+ 線程間通信常用方法

```objc
-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
-(void)performSelector:(SEL)aSelectoron Thread:(NSThread*)thread withObject:(id)arg waitUntilDone:(BOOL)wait;

2、應(yīng)用

1、買票:互斥鎖,解決多線程搶奪同一資源問題

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) NSThread *thread1; /**< 售票員1 */
@property (nonatomic, strong) NSThread *thread2; /**< 售票員2 */
@property (nonatomic, strong) NSThread *thread3; /**< 售票員2 */

@property (nonatomic, assign)NSUInteger totalCount; /**< 票的總數(shù) */
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 0.初始化票數(shù)
    self.totalCount = 100;
    // 1.創(chuàng)建3個(gè)售票員
    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    thread1.name = @"售票員1";
    self.thread1 = thread1;
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    thread2.name = @"售票員2";
    self.thread2 = thread2;
    NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
    thread3.name = @"售票員3";
    self.thread3 = thread3;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 2.讓3個(gè)售票員同事售票
    [self.thread1 start];
    [self.thread2 start];
    [self.thread3 start];
}

// 售票方法
- (void)saleTicket
{
    while (1) {
        
        NSLog(@"歡迎光臨");
        // 只要被synchronized擴(kuò)住的代碼, 就是被鎖住的代碼 \
        也就是說, 只要被synchronized{}擴(kuò)住, 就能實(shí)現(xiàn)同一時(shí)刻, 只能有一個(gè)線程操作
        
        /*
        // 注意:
        // 1. 如果多條線程訪問同一個(gè)資源, 那么必須使用同一把鎖才能鎖住
        // 2. 在開發(fā)中, 盡量不要加鎖, 如果必須要加鎖, 一定記住, 鎖的范圍不能太大, 哪里會(huì)有安全隱患就加在哪里
         */
//         NSObject lockObj = [[NSObject alloc] init];
        /*
        技巧: 
         1.@synchronized單詞的快速記憶方法  [NSUserDefaults standardUserDefaults] synchronize + d
         2.開發(fā)中如果需要加鎖, 一般都使用self
         */
       
        // 線程2: 等待,  線程3: 等待
        @synchronized(self){ // 鎖住
        
            // 1.查詢剩余的票數(shù)
            NSUInteger count = self.totalCount;
            // 2.判斷是否還有余票
            if (count > 0) {
                // 線程1 100
                [NSThread sleepForTimeInterval:0.1];
                // 2.1賣票
                self.totalCount = count - 1; // 99
                NSLog(@"%@賣了一張票, 還剩%zd票", [NSThread currentThread].name, self.totalCount);
            }else
            {
                // 3.提示客戶, 沒有票了
                NSLog(@"對(duì)不起, 沒有票了");
                break;
            }
        } // 解鎖
    
    }   
}
@end
  1. 線程間通信
  • 實(shí)例:在子線程中下載圖片,回到主線程刷新界面
  • 代碼實(shí)現(xiàn):如下
#import "ViewController.h"
@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end

@implementation ViewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"%s", __func__);
    
    // 開啟一個(gè)子線程下載圖片
    [self performSelectorInBackground:@selector(downlod) withObject:nil];
}

- (void)downlod
{
    NSLog(@"%@", [NSThread currentThread]);
    // 1.下載圖片
     NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/img/bd_logo1.png"];
     NSData *data = [NSData dataWithContentsOfURL:url];
    // 2.將二進(jìn)制轉(zhuǎn)換為圖片
    UIImage *image = [UIImage imageWithData:data];
    
    // 3.跟新UI
#warning 注意: 千萬不要在子線程中更新UI, 會(huì)出問題
//    self.imageView.image = image;
    
    /*
     waitUntilDone: 
     YES: 如果傳入YES, 那么會(huì)等待updateImage方法執(zhí)行完畢, 才會(huì)繼續(xù)執(zhí)行后面的代碼
     NO:  如果傳入NO, 那么不會(huì)等待updateImage方法執(zhí)行完畢, 就可以繼續(xù)之后后面的代碼
     */
    /*
    [self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:NO];
    
    NSLog(@"------------");
     */
    
    // 開發(fā)中常用
//    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
    
    // 可以在指定的線程中, 調(diào)用指定對(duì)象的指定方法
    [self performSelector:@selector(updateImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
    
}

- (void)updateImage:(UIImage *)image
{
    NSLog(@"%@", [NSThread currentThread]);
    // 3.更新UI
    self.imageView.image = image;
}
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文地址 http://www.cnblogs.com/kenshincui/p/3983982.html 大家都...
    怎樣m閱讀 1,423評(píng)論 0 1
  • .一.進(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,604評(píng)論 1 33
  • 多線程基本概念 單核CPU,同一時(shí)間cpu只能處理1個(gè)線程,只有1個(gè)線程在執(zhí)行 。多線程同時(shí)執(zhí)行:是CPU快速的在...
    WeiHing閱讀 786評(píng)論 1 5
  • 一、多線程基礎(chǔ) 基本概念 進(jìn)程進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且...
    AlanGe閱讀 650評(píng)論 0 0
  • 今天世界讀書日,我不讀書,是要反省讀書。 書到用時(shí)方恨少,好大的道理!可是我讀了一肚子的讀者文摘和名家散文,只曉得...
    樂讀書房_李葵閱讀 489評(píng)論 0 4

友情鏈接更多精彩內(nèi)容