天天看點

iOS之線程的概念和NSThread(一)

1. 基礎概念

1.1程序:一個

運作

的應用程式,就是一個程序(比如:你iphone上的QQ,微信,MAC電腦上的迅雷,Xcode等)
  • 每一個程序之間是互相獨立的,在記憶體中開辟空間
  • 一個打開應用程式不一定是一個程序(比如:QQ程式,你開啟多個QQ賬号登入,就

    對應的多個程序

    )
線程:一個程序要執行任務的片段,一條程序至少要有一個線程
  • 一個應用程式的所有任務都要在

    線程

    中執行

多線程:是一個程序開啟了多條線程,每條線程同時執行不同的任務

主線程

  • iOS程式運作之後,預設開啟一條線程,成為主線程或者UI線程
  • 主線程是用來:重新整理UI界面,處理UI事件

使用分類

技術 簡介 語言 周期
NSThread [1]面向對象 [2]可直接操作線程 OC 程式員自己管理 -> 偶爾使用
GCD [1]代替NSThread 【2】充分利用CPU多核 C 程式員自己管理 -> 使用次數頻繁
NSOperation [1]基于GCD 【2】面向對象操作 OC 程式員自己管理 -> 使用次數頻繁

2.NSThread 線程

2.1基礎認知
  • 擷取主線程
NSThread *main = [NSThread mainThread];
    NSLog(@"%@",main);
   
           
  • 擷取目前線程
//擷取目前線程
    NSThread *current = [NSThread currentThread];
    NSLog(@"-----%@",current);
           
  • 設定線程的名稱屬性

    name

    屬性
  • 設定線程的優先級

    threadPriority

    屬性,

    範圍0.0-1.0 (預設是0.5)

2.2建立子線程 方法一
//開啟一個線程
- (void)setupTh {
    /*
     *參數一:目标對象
     * 參數二:要執行的g方法
     * 參數三:要執行的方法需要傳入的參數值
     */
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction:) object:@"test"];
    //設定線程的名稱
     thread.name = @"CC";
    //啟動線程
    [thread start];
    
    
}

//要執行的方法
- (void)handleThreadAction:(NSString *)par {
    
    NSLog(@"---%@----%@",[NSThread currentThread],par);
}
//列印結果
 ---<NSThread: 0x600003495fc0>{number = 3, name = CC}----test


           
2.3 建立子線程 方法二
- (void)setupTwo {
    //參數和 方法一的參數 類似
    [NSThread detachNewThreadSelector:@selector(handleThreadAction:) toTarget:self withObject:@"text"];
 
}

- (void)handleThreadAction:(NSString *)par {
    NSLog(@"---%@----%@",[NSThread currentThread],par);
    NSLog(@"%@",[NSThread isMainThread] == YES ? @"是" :@"不是");
   
}

//列印
---<NSThread: 0x6000004da8c0>{number = 3, name = (null)}----text
06-03 16:26:23.173228+0800 01-線程[20338:241267] 不是

           

3. 隐式線程

- (void)setupThress {
    //開啟一個背景子線程
    //這個方法的參數 和 上面建立子線程的類似
    [self performSelectorInBackground:@selector(handleThreadAction:) withObject:@"建立放大--"];
}

- (void)handleThreadAction:(NSString *)par {
    
    NSLog(@"---%@----%@",[NSThread currentThread],par);
    NSLog(@"%@",[NSThread isMainThread] == YES ? @"是" :@"不是");
}

           
NSThread線程的生命周期是,當任務執行完成才後被釋放這個對象

4.線程的安全問題

出現這個問題的原因,一般為多人同時通路的

共有資源

的時候,會導緻資源的覆寫或者資源資料出錯(比如:售票)
4.1互斥(同步)鎖
@synchronized ("全局屬性") {
    //要枷鎖的代碼
}
           
  • 互斥鎖的條件
    • 必須是全局

      唯一的對象

    • 多線程

      共享同一塊資源

  • 互斥鎖的結果
    • 線程同步執行
    • 耗費性能
- (void)saleoftickets{
    
    self.read1 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
  
    self.read2 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
    
    self.read3 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
    
     self.read1.name = @"售票TT";
    self.read2.name = @"售票CC";
    self.read3.name = @"售票BB";
    //啟動線程
    [self.read1 start];
    //啟動線程
    [self.read2 start];
    //啟動線程
    [self.read3 start];
    
}

//執行方法

- (void)handleThreadAction{
    
    // synchronized 是消耗性能的,線程使用的鎖對象 必須是同一個對象
    // 可以定義一個屬性對象 
    while (1) {
        @synchronized (self) {
            
            for (int i = 0; i < 1000; i ++) {
                
            }
            
            NSUInteger accunt = self.acount;
            
            if (accunt > 0) {
                self.acount = accunt - 1;
                NSLog(@"%@----%ld",[NSThread currentThread].name,self.acount);
                
            }else {
                NSLog(@"售完了。。。。");
                break;
            }
            
        }
        
        
    }
    
   
}

           

4.2原子屬性和非原子屬性

  • nonatomic

    非原子屬性,沒有加互斥鎖
  • atomic

    原子屬性,為了線程安全,在

    setter

    加互斥鎖

5.線程之間的通信

  • 線程之間通信常用的方法
//在子線程中調用 這個方法 就是回到主線程 進行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait


// 從一個線程跳轉到另外一個線程執行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

           
主要用于:圖檔下載下傳異步操作

6.線程阻塞

- (void)sleepThread {
    //阻塞2秒
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
    
    //阻塞到遙遠的未來
    [NSThread sleepUntilDate:[NSDate distantFuture]];
}