多線程 - 課程分析

     1.每個進程至少包含一個線程,這個默認創建的線程被成爲主線程
     2.單線程程序:程序只包含一個線程(主線程),線程中的代碼按順序執行,缺點:可能會造成主線程阻塞(有些任務耗時比較長)
     3.多線程程序:程序中包含多個線程,線程是獨立運行的,提高程序運行效率.
     4.iOS開發中,所有跟UI有關的操作(繪製,刷新)都必須在主線程中完成.
     5.子線程:主線程之外創建的新的線程
     

     △.線程是可以設置優先級的


獲取當前線程,判斷是否是主線程的方法:

     NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);


     先創建一個多線程測試環境:

-(void)cycle
{
    //獲取當前線程,判斷是否是主線程
    NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    
    int sum = 0;
    for (int i=0; i<500; i++) {
        sum += i;
//        NSLog(@"%d",i);
    }
//    NSLog(@"%d",sum);
}

      一 . 使用NSThread實現多線程 : 創建線程後,自動開啓,無需手動調用開啓

     1.第一個參數:線程中需要執行的方法
     2.第二個參數:執行方法的對象
     3.第三個參數:傳值

    [NSThread detachNewThreadSelector:@selector(cycle) toTarget:self withObject:nil];


      二 . 使用NSThread實現多線程 : 創建線程後,需要手動開啓


    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(cycle) object:nil];
    [thread start];

       三 . 使用NSObject類目方法實現多線程(用的比較多)

    //隱式創建線程
    [self performSelectorInBackground:@selector(cycle) withObject:nil];
    
    //圖片網址
    NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";
    [self performSelectorInBackground:@selector(downloadImage:) withObject:url];


//在子線程中,同步連接下載圖片
-(void)downloadImage:(NSString *)url
{
    
    //在子線程中,使用同步方式下載圖片.  △備註:在子線程中,不要使用異步連接,會出現問題
    
    /*
     △注意事項:
     1.子線程中沒有自動釋放池,需要手動添加
     2.NSThread創建的子線程,默認情況下,任務執行完成後,線程被關閉,銷燬
     3.在子線程中,NSTimer默認情況下,不會執行.如果在子線程中使用NSTimer,必須開啓runLoop,方法如下:
     4.所有線程都有runLoop,主線程默認是開啓狀態,子線程默認是關閉狀態
     5.子線程開啓runLoop後,runLoop不停止,線程無法關閉
     */
    
    //獲取當前線程的runLoop,並開啓
//    [[NSRunLoop currentRunLoop] run];
    //獲取當前線程的runLoop,並設定運行的時間
//    [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];
    
    
    //獲取當前線程,判斷是否是主線程
    NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    
    
    //同步下載圖片
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
    //將data轉換成image對象
    UIImage *image = [UIImage imageWithData:data];
    
    //△注意:將image在主線程中進行顯示.
//    _imageView.image = image;//這句話位置不對,不能寫在這裏
    [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];//第三個參數:等待子線程任務執行完成,再回到主線程執行
    
    //直接給imageView附圖片
//    [_imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
    
}
//在主線程中,將image顯示在imageView上
-(void)showImage:(UIImage *)image
{
    //獲取當前線程,判斷是否是主線程
    NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    
    //參數image是從子線程中返回
    _imageView.image = image;
    
}

        四 . NSOperation 是一個操作類(抽象類),封裝了需要執行的任務和數據.   一般不直接使用NSOperation,使用子類:NSInvocationOperation和NSBlockOperation

    //操作對象封裝了需要執行的任務和參數
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];
    //開始執行operation對象中封裝的任務(方法)
    //start在哪個線程中調用,operation對象中封裝的方法就在哪個線程中執行
    [operation start];

       五 . block方法:

    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"當前線程 %@ ----- 是否是主線程:%d", [NSThread currentThread], [NSThread isMainThread]);
        
        for (int i = 1; i < 500; i++) {
            
        }
    }];
    
    [operation start];

       六 . NSOperationQueue :

      1.NSOperationQueue  操作隊列(先進先出),可以管理多個操作對象.
      2.NSOperationQueue  創建的多線程是可以重複使用的,是非脫離線程(線程中的任務完成後,線程進入睡眠狀態,未被銷燬;NSThread創建的線程是脫離線程)
      3.NSOperationQueue  先加入隊列的任務,先執行.(即"先進先出")
      4.NSOperationQueue  控制的線程是併發執行的. 即:隊列中的任務按照加入隊列的順序進行分派,但是下一個任務不用等待前一個任務完成再開始.多個任務可以同時執行,互不干擾.  ("併發"相對的是"串行")
      5.什麼叫線程同步?  線程A執行結束後才能執行線程B
      6.NSOperationQueue如何實現線程同步?  把最大併發數設置爲1,即:每次只允許一個線程執行任務
      7.隊列下載

    NSOperationQueue * queue = [[NSOperationQueue alloc]init];
    
    //設置最大併發數
    queue.maxConcurrentOperationCount = 1;
    
    //添加10個任務
    for (int i=0; i<10; i++) {
        NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];
        //操作對象添加到隊列裏
        [queue addOperation:operation];
    }

      七 . 使用GCD的隊列實現串行(任務1執行後,任務2再執行) :

     1.GCD隊列類型:主隊列,全局隊列,自定義隊列
     2.GCD隊列功能:串行,併發
     3.能夠實現串行的有兩種隊列:主隊列和自定義串行隊列
     4.能夠實現併發的有兩種隊列:全局隊列和自定義併發隊列


//串行隊列 第一種實現:使用主隊列
    /*
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    //向隊列異步添加任務
    dispatch_async(queue, ^{
        NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    */
     
    //串行隊列 第二種實現:使用自定義串行隊列
    dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    
    //釋放(注意:MRC下需要釋放)
//    dispatch_release(queue);

        八 . GCD併發:任務A,B,C....按照進入隊列順序開始分派執行

    //併發隊列 第一種實現:全局隊列
    /*
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    */
    
    //併發隊列 第二種實現:使用自定義併發隊列
    
    dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
    });

         九 . GCD

    //在子線程中建立同步連接下載圖片(把任務添加到全局隊列)
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        
        //建立同步連接下載圖片
        //圖片網址
        NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
        UIImage *image = [UIImage imageWithData:data];
        
        NSLog(@"同步連接下載圖片,當前線程:%@",[NSThread currentThread]);
        
        //在主線程中,顯示下載的圖像
        dispatch_async(dispatch_get_main_queue(), ^{
            
            _imageView.image = image;
            NSLog(@"顯示下載圖片,當前線程:%@",[NSThread currentThread]);
            
        });
        
    });

         十 . 總結:

1.耗費時間的兩種方式:下載(跟網速有關)和處理數據

2.  任務               線程           方法
  觸發下載圖片          主線程       didClick....Button
  建立同步連接下載圖片   子線程        download

3.
/*
1.每個進程至少包含一個線程,這個默認創建的線程被成爲主線程
2.單線程程序:程序只包含一個線程(主線程),線程中的代碼按順序執行,缺點:可能會造成主線程阻塞(有些任務耗時比較長)
3.多線程程序:程序中包含多個線程,線程是獨立運行的,提高程序運行效率.
4.iOS開發中,所有跟UI有關的操作(繪製,刷新)都必須在主線程中完成.
5.子線程:主線程之外創建的新的線程

△.線程是可以設置優先級的
*/

4.
/*
△注意事項:
1.子線程中沒有自動釋放池,需要手動添加
2.NSThread創建的子線程,默認情況下,任務執行完成後,線程被關閉,銷燬
3.在子線程中,NSTimer默認情況下,不會執行.如果在子線程中使用NSTimer,必須開啓runLoop,方法如下:
4.所有線程都有runLoop,主線程默認是開啓狀態,子線程默認是關閉狀態
5.子線程開啓runLoop後,runLoop不停止,線程無法關閉
*/

//獲取當前線程的runLoop,並開啓
//    [[NSRunLoop currentRunLoop] run];
//獲取當前線程的runLoop,並設定運行的時間
//    [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];

5.

/*

1.NSOperationQueue  操作隊列(先進先出),可以管理多個操作對象.
2.NSOperationQueue  創建的多線程是可以重複使用的,是非脫離線程(線程中的任務完成後,線程進入睡眠狀態,未被銷燬;NSThread創建的線程是脫離線程)
3.NSOperationQueue  先加入隊列的任務,先執行.(即"先進先出")
4.NSOperationQueue  控制的線程是併發執行的. 即:隊列中的任務按照加入隊列的順序進行分派,但是下一個任務不用等待前一個任務完成再開始.多個任務可以同時執行,互不干擾.  ("併發"相對的是"串行")
5.什麼叫線程同步?  線程A執行結束後才能執行線程B
6.NSOperationQueue如何實現線程同步?  把最大併發數設置爲1,即:每次只允許一個線程執行任務
7.隊列下載
*/

6.
△.注意:GCD不等於多線程


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章