1.基本概念併發
/** 串行隊列 */ - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //串行隊列,同步方法 [self serailSync]; //串行隊列,異步方法 // [self serailAsync]; } /** 串行隊列,異步方法 1.打印順序 : 從上到下依次執行,它是串行隊列 2.在哪條線程上執行:在子線程,由於它是異步執行,異步,就是不在當前線程裏面執行 應用場景:耗時間,有順序的任務 1.登陸--->2.付費--->3.才能看 */ - (void)serailAsync{ //1.建立一個串行隊列 /** 參數1:隊列的標識fuhao,通常是公司的域名倒寫 www.itheima.com 參數2:隊列的類型 DISPATCH_QUEUE_SERIAL 串行隊列 DISPATCH_QUEUE_CONCURRENT 併發隊列 */ dispatch_queue_t serialQueue = dispatch_queue_create("com.itheima.queue1", DISPATCH_QUEUE_SERIAL); //2.建立三個任務 void (^task1) () = ^(){ NSLog(@"task1---%@",[NSThread currentThread]); }; void (^task2) () = ^(){ NSLog(@"task2---%@",[NSThread currentThread]); }; void (^task3) () = ^(){ NSLog(@"task3---%@",[NSThread currentThread]); }; //3.把咱們上面建立好的三個任務,添加到隊列中去,這個隊列就會本身開始調用咱們的任務 //異步方法執行 dispatch_async(serialQueue, task1); dispatch_async(serialQueue, task2); dispatch_async(serialQueue, task3); } /** 串行隊列,同步方法 1.打印順序 : 從上到下,依次打印,由於串行的 2.在哪條線程上執行:主線程,由於是同步方法,因此在當前線程裏面執行,剛好當前線程是主線程,因此它就在主線程上面執行 應用場景:開發中不多用 */ - (void)serailSync{ //1.建立一個串行隊列 /** 參數1:隊列的標識fuhao,通常是公司的域名倒寫 www.itheima.com 參數2:隊列的類型 DISPATCH_QUEUE_SERIAL 串行隊列 DISPATCH_QUEUE_CONCURRENT 併發隊列 */ dispatch_queue_t serialQueue = dispatch_queue_create("com.itheima.queue1", DISPATCH_QUEUE_SERIAL); //2.建立三個任務 void (^task1) () = ^(){ NSLog(@"task1---%@",[NSThread currentThread]); }; void (^task2) () = ^(){ NSLog(@"task2---%@",[NSThread currentThread]); }; void (^task3) () = ^(){ NSLog(@"task3---%@",[NSThread currentThread]); }; //3.把咱們上面建立好的三個任務,添加到隊列中去,這個隊列就會本身開始調用咱們的任務 //同步方法執行 dispatch_sync(serialQueue, task1); dispatch_sync(serialQueue, task2); dispatch_sync(serialQueue, task3); }
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //1.併發隊列,同步任務 //[self concurrentSync]; //2.併發隊列,異步任務 [self concurrentAsync]; } - (void)concurrentAsync{ /** 併發隊列,異步方法 1.打印順序 :無序的 2.在哪條線程上執行:在子線程上執行,第一個任務,都在它本身的線程上執行 開N條,它是由底層可調度線程池來決定的,可調度線程池它是有一個重用機制 應用場景: 半月轉 開頭 中間 結尾 下載電視劇某一集的時候,能夠把咱們的片頭,片尾,中間內容 一塊兒下 最後,拼接組合一下,就能夠播放了 片頭,中間內容,片尾 */ //1.建立一個併發的隊列 dispatch_queue_t concurrentQueue = dispatch_queue_create("com.itheima.queue2", DISPATCH_QUEUE_CONCURRENT); //2.建立三個任務 void (^task1) () = ^(){ NSLog(@"task1---%@",[NSThread currentThread]); }; void (^task2) () = ^(){ NSLog(@"task2---%@",[NSThread currentThread]); }; void (^task3) () = ^(){ NSLog(@"task3---%@",[NSThread currentThread]); }; //3.將咱們的三個任務,添加到隊列中 //異步方法去執行 dispatch_async(concurrentQueue, task1); dispatch_async(concurrentQueue, task2); dispatch_async(concurrentQueue, task3); } /** 併發隊列,同步方法 1.打印順序 : 依次執行,由於它是同步的 2.在哪條線程上執行:主線程,由於它是同步方法,它就在當前線程裏面執行,主線程,依次執行 當它遇到同步的時候,併發隊列,仍是依次執行 因此說,方法的優先級會比隊列的優先級高 * 只要是同步方法,都只會在當前線程裏面執行,不會開子線程 應用場景: 開發中幾乎不用 */ - (void)concurrentSync{ //1.建立一個併發的隊列 dispatch_queue_t concurrentQueue = dispatch_queue_create("com.itheima.queue2", DISPATCH_QUEUE_CONCURRENT); //2.建立三個任務 void (^task1) () = ^(){ NSLog(@"task1---%@",[NSThread currentThread]); }; void (^task2) () = ^(){ NSLog(@"task2---%@",[NSThread currentThread]); }; void (^task3) () = ^(){ NSLog(@"task3---%@",[NSThread currentThread]); }; //3.將咱們的三個任務,添加到隊列中 //同步方法去執行 dispatch_sync(concurrentQueue, task1); dispatch_sync(concurrentQueue, task2); dispatch_sync(concurrentQueue, task3); }
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //1.主隊列,異步 [self mainAsync]; //2.主隊列,同步 //[self mainSync]; } /** 主隊列,同步任務有問題,不能用 `主隊列`只有在`主線程空閒`的時候,纔會去調度它裏面的任務去執行 */ - (void)mainSync{ //只是用來調試,說明咱們來到了這個方法 NSLog(@"%s",__func__); //1.獲取主隊列 dispatch_queue_t mainQueue = dispatch_get_main_queue(); //2.搞三個任務 void (^task1) () = ^(){ NSLog(@"task1===%@",[NSThread currentThread]); }; void (^task2) () = ^(){ NSLog(@"task2===%@",[NSThread currentThread]); }; void (^task3) () = ^(){ NSLog(@"task3===%@",[NSThread currentThread]); }; //3.將任務添加到主隊列中 dispatch_sync(mainQueue, task1); dispatch_sync(mainQueue, task2); dispatch_sync(mainQueue, task3); NSLog(@"mainSync----end"); } /** 主隊列,異步任務 1.執行順序:依次執行,由於它在主線程裏面執行 * 彷佛與咱們的異步任務有所衝突,可是由於它是主隊列,因此,只在主線程裏面執行 2.是否會開線程:不會開,由於它在主線程裏面執行 應用場景: 當作了耗時間操做以後,當咱們須要回到主線程更新UI的時候,就非它不可 */ - (void)mainAsync{ //1.獲取主隊列 dispatch_queue_t mainQueue = dispatch_get_main_queue(); //2.搞三個任務 void (^task1) () = ^(){ NSLog(@"task1===%@",[NSThread currentThread]); }; void (^task2) () = ^(){ NSLog(@"task2===%@",[NSThread currentThread]); }; void (^task3) () = ^(){ NSLog(@"task3===%@",[NSThread currentThread]); }; //3.將任務添加到主隊列中 dispatch_async(mainQueue, task1); dispatch_async(mainQueue, task2); dispatch_async(mainQueue, task3); NSLog(@"---mainAsync---end"); }
2.經常使用代碼異步
/** 若是要在子線程中執行 除了`主隊列`均可以,串行,併發,全局均可以 去主線程只有一個方法,那就是主隊列,異步 */ dispatch_async(dispatch_get_global_queue(0, 0), ^{ //1.去子線程裏面加載圖片 NSLog(@"僞裝在下載...%@",[NSThread currentThread]); [NSThread sleepForTimeInterval:3.0]; //2.去主線程更新UI dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"%@----更新UI",[NSThread currentThread]); }); });
3.同步的做用async
/** 同步的做用:保證咱們任務執行的前後順序 1.登陸 2.同時下載三部小電影 */ - (void)execLongTimeOperation{ dispatch_async(dispatch_get_global_queue(0, 0), ^{ //1.登陸,同步在當前線程裏面工做 dispatch_sync(dispatch_get_global_queue(0, 0), ^{ NSLog(@"%@----登陸...",[NSThread currentThread]); [NSThread sleepForTimeInterval:3.0]; }); //2.同時下載三部小電影(不須要前後順序) dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"downLoadA----%@",[NSThread currentThread]); }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"downLoadV----%@",[NSThread currentThread]); }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"downLoadI----%@",[NSThread currentThread]); }); }); }
4.延遲操做ide
/** 參數1.延時多少納秒,整個延遲3秒 參數2:是決定,參加在哪一個線程裏面調用 參數3:任務執行的代碼塊 dispatch_after 異步的 應用場景: 動畫 */ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"---下載完畢---%@",[NSThread currentThread]); }); NSLog(@"---end---");
5.單例函數
+ (instancetype)sharedNetWorkToos;
static id _instance; + (instancetype)sharedNetWorkToos{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } + (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } - (id)copyWithZone:(NSZone *)zone{ return _instance; }
6.調度組,組內的線程所有執行完,會到dispatch_group_notify定義的方法中oop
//1.建立一個調度組 dispatch_group_t group = dispatch_group_create(); //2.獲取全局隊列 dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); //3.三個下載任務 void (^task1) () = ^(){ NSLog(@"%@----下載片頭",[NSThread currentThread]); }; void (^task2) () = ^(){ NSLog(@"%@----下載中間的內容",[NSThread currentThread]); [NSThread sleepForTimeInterval:5.0]; NSLog(@"--下載中間內容完畢---"); }; void (^task3) () = ^(){ NSLog(@"%@----下載片尾",[NSThread currentThread]); }; //3.須要將咱們的隊列和任務,加入組內去監控 dispatch_group_async(group, globalQueue, task1); dispatch_group_async(group, globalQueue, task2); dispatch_group_async(group, globalQueue, task3); //4.監聽的函數 /** 參數1:組 參數2:參數3在哪一個線程裏面執行 參數3:組內徹底下載完畢以後,須要執行的代碼 */ dispatch_group_notify(group, dispatch_get_main_queue(), ^{ //表示組內的全部任務都完成以後,會來到這裏 NSLog(@"把下好的視頻按照順序拼接好,而後顯示在UI去播放"); });
調度組的實現原理動畫
/** 應用場景 好比我去同時開三個線程下載視頻,只有當三個視頻徹底下載完畢以後,我才能作後續的事, 這個就須要用到調度組,這個調度組,就能監聽它裏面的任務是否都執行完畢 */ - (void)execGroupDispatch{ //1.建立一個調度組 dispatch_group_t group = dispatch_group_create(); //2.獲取全局隊列 dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); //3.三個下載任務 dispatch_group_enter(group); //引用計數+1 void (^task1) () = ^(){ NSLog(@"%@----下載片頭",[NSThread currentThread]); dispatch_group_leave(group); //引用計數-1 }; dispatch_group_enter(group); //引用計數+1 void (^task2) () = ^(){ NSLog(@"%@----下載中間的內容",[NSThread currentThread]); [NSThread sleepForTimeInterval:5.0]; NSLog(@"--下載中間內容完畢---"); dispatch_group_leave(group);//引用計數-1 }; void (^task3) () = ^(){ NSLog(@"%@----下載片尾",[NSThread currentThread]); }; //3.須要將咱們的隊列和任務,加入組內去監控 dispatch_group_async(group, globalQueue, task1); dispatch_group_async(group, globalQueue, task2); dispatch_group_async(group, globalQueue, task3); //4.監聽的函數 /** 參數1:組 參數2:參數3在哪一個線程裏面執行 參數3:組內徹底下載完畢以後,須要執行的代碼 */ dispatch_group_notify(group, dispatch_get_main_queue(), ^{ //表示組內的全部任務都完成以後,會來到這裏 NSLog(@"把下好的視頻按照順序拼接好,而後顯示在UI去播放"); }); }
7.定時器與運行循環atom
@interface ViewController () @property (nonatomic, assign) int count; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self performSelectorInBackground:@selector(subThreadRun) withObject:nil]; } - (void)subThreadRun{ NSLog(@"%s----%@",__func__,[NSThread currentThread]); //1.定義了一個定時器 NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timeEvent) userInfo:nil repeats:YES]; //2.將咱們的定時器加入到運行循環,只有加入到當前的運行循環裏面去,他才知道你這個時候,有一個定時任務 /** NSDefaultRunLoopMode 當拖動的時候,它會停掉 由於這種模式是互斥的 forMode:UITrackingRunLoopMode 只有輸入的時候,它纔會去執行定時器任務 NSRunLoopCommonModes 包含了前面兩種 */ //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; //下載,定時源事件,輸入源事件,若是放在子線程裏面,若是想要它執行任務,就必須開啓子線程的運行循環 CFRunLoopRun(); } - (void)timeEvent{ self.count ++; NSLog(@"%d",self.count); if (self.count==5) { NSLog(@"---guale---"); //中止當前的運行循環 CFRunLoopStop(CFRunLoopGetCurrent()); } }