線程與進程的關系:
1>進程和應用程序的關系:進程為應用程序開辟內存空間
2>程和應用程序的關系:線程執行應用程序中的代碼
3>進程和線程的關系:進程是由線程組成的,一個進程至少包含一條線程(主線程)
runloop和線程有什么關系?
1.每一個線程中都?個runloop,只有主線的的runloop默認是開啟的,其他線程的runloop是默認沒有開啟的
2.可以通過CFRunLoopRun()函數來開啟?一個事件循環
3.看SDWebImage源碼的時候?到有這么?過.
runloop的model作用是什么?
model主要是用來指定時間在運行循環中的優先級的 蘋果公開提供的Mode有兩個:
kCFRunLoopDefaultMode
kCFRunLoopCommonModes
如果我們把一個NSTimer對象以kCFRunLoopDefaultMode添加到主運行循環中的時候,當一直 有用戶事件處理的時候,NSTimer將不再被調度 如果我們把一個NSTimer對象以kCFRunLoopCommonModes添加到主運行循環中的時候,當一 直有用戶事件處理的時候,NSTimer還能正常的調度,互不影響.
runloop內部的實現:
1.他是一個死循環
2.如果事件隊列中存放在事件,那就取出事件,執?行相關代碼
3.如果沒有事件,就掛起,等有事件了,?立即喚醒事件循環,開始執?
在多線程的中使用block:
block在管理子線程以及線程的創建個銷毀是由隊列負責的,直接在block中使用self沒有關系,不會造成循環引用
多線程:就是多條線程,也指并發編程
多線程的底層是通過Mach實現的
開發多線程的多種方案:
1>C語言POSIX接口:#include
2>OC的NSThread
3>C語言的CGD接口( 性能最好 , 代碼最精簡 )
4>OC的NSOperationn和NSOperationQueue (基于CGD)
線程間通信:
//最后一個參數:是否等待調用方法執行結束!
<1>[selfperformSelectorOnMainThread:@selector(setImageWithImage:) withObject:nilwaitUntilDone:YES];
<2>[selfperformSelector:@selector(setImageWithImage:) onThread:[NSThread mainThread] withObject:nilwaitUntilDone:YES];
3>經典組合:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{
//在這里執行耗時操作
dispatch_async(dispatch_get_main_queue(), ^{
//在這里更新UI界面
});
});
一般通信會使用在子線程下載數據,做一些耗時操作,在主線程更新UI界面
使用NSThread開啟線程的方式
//創建線程的幾種方式
//1>直接創建一條子線程
NSThread*thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(run)object:nil];
//開啟線程
[threadstart];
//獲取主線程
[NSThreadmainThread];
//檢測當前線程是否為主線程
NSLog(@"%d",[NSThreadisMainThread]);
//2獲取當前線程
NSThread*currentThread = [NSThreadcurrentThread];
//判斷當前線程的狀態(線程所處的位置)
BOOLis = [currentThreadisMainThread];
//設置線程的名字
[currentThreadsetName:@"123"];
//3直接創建一條線程
[NSThreaddetachNewThreadSelector:@selector(run1)toTarget:selfwithObject:nil];
//4開啟一條隱式線程
[selfperformSelectorInBackground:@selector(run1)withObject:nil];
線程的生命周期:
新建一個線程->開啟->等待CPU調度->執行任務/強制退出/異常->線程結束/死亡
注意:一旦線程死亡之后,就不會被調度,也就是不會再執行該線程中任務
線程的阻塞:
1>在開啟線程之后,如果執行了[NSThreadsleepForTimeInterval:3.0];或者是加了互斥鎖,都會導致線程阻塞blocked
2>在CPU調度線程后,線程中的任務正在執行 ,如果執行了[NSThreadsleepForTimeInterval:3.0];或者是加了互斥鎖,都會導致線程阻塞blocked
線程之間資源共享問題:
同一個資源被多條線程同時訪問的時候會造成數據信息錯誤的問題 例子:在不同的地方同一時間去ATM取錢,一個在存.一個在取
問題解決方案:
添加互斥鎖
@synchronized(鎖對象) {//需要鎖定的代碼}
注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的
互斥鎖的優缺點
優點:能有效防止因多線程搶奪資源造成的數據安全問題
缺點:需要消耗大量的CPU資源
互斥鎖的使用前提:多條線程搶奪同一塊資源
相關專業術語:線程同步
線程同步的意思是:多條線程在同一條線上執行(按順序地執行任務)
互斥鎖,就是使用了線程同步技術
添加互斥鎖的技巧 :[[NSUserDefaultsstandardUserDefaults]synchronize];利用此行代碼可以敲出@synchronized
同步函數(sync)和異步函數 (async)與 線程之間的關系:
1>同步函數 + 串行隊列 : 沒有開啟新線程,串行執行任務
2>同步函數 + 并行隊列 : 沒有開啟新線程,串行執行任務
3>同步函數 + 主隊列 : 沒有開啟新線程 ?,卡住主線程
總結:同步函數執行任何類型隊列,都不會開啟新線程;都是在當前線程執行任務,同步函數不具備開啟新線程的能力
1>異步函數 +?串行隊列 : 會開啟一條新的線程,并且任務按順序執行
2>異步函數 + 并行隊列 : 會開啟多條子線程,任務同時執行
3>同步函數 + 主隊列 : 沒有開啟新線程,任務按順序執行
注意:使用sync函數往當前串行隊列添加任務,會卡住當前的串行隊列.
GCD的隊列(dispatch_queue_t)分哪兩種類型?
串?行隊列和并?行隊列
隊列決定了操作是在主線程執行還是子線程執行
如何用GCD同步若干個異步調用?(如根據若干個url異步加載多張 圖片,然后在都下載完成后合成一張整圖)
1.創建異步隊列
2.創建dispatch_group_tdispatch_group_t? =dispatch_group_create();3.通過組來執?行異步下載任務
dispatch_group_async(dispatch_group_t, dispatch_queue_t, ^{
NSLog(@"下載圖片");
});
4.等到所有任務完成
dispatch_group_wait(dispatch_group_t,DISPATCH_TIME_FOREVER);
5.合成圖?
dispatch_barrier_async的作用是什么?
barrier:是障礙物的意思,在多個并?行任務中間,他就像是?一個隔離帶,把前后的并?行任務分開.dispatch_barrier_async作?用是在并?行隊列中,等待前?面操作并?行任務完成 在執?行dispatch_barrier_async中的任務 如果后?面還有并?行任務,會開始執?行后續的并?行任務
蘋果為什么要廢棄dispatch_get_current_queue?
容易誤?用造成死鎖
- (void)viewDidLoad {
[superviewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}只能輸出1,然后線程主線程鎖死
有4個術語比較容易混淆:同步、異步、并發、串行
同步和異步主要影響:能不能開啟新的線程
同步:在當前線程中執行任務,不具備開啟新線程的能力
異步:在新的線程中執行任務,具備開啟新線程的能力
并發和串行主要影響:任務的執行方式
并發:多個任務并發(同時)執行
串行:一個任務執行完畢后,再執行下一個任務
>同步函數:同步就是順序依次執行,如果在子線程上就是在子線程處理,但是不會建立新線程
>只在主線程上操作
dispatch_sync(dispatch_get_main_queue()^{
})
1.1在主線程操作會遵循PIPE的隊列順序去操作
1.2但是這樣資源一旦多了起來就會導致主線程堵塞
>同步并發處理
>什么是并發
并發是在同一條線程內開啟多個隊列一起處理,就比如你玩游戲在玩MMORPG的時候你打怪物的同時怪物也在攻擊你,這就是并發.
dispatch_sync(dispatch_get_glodal_queue(0,0), ^{
//括號(0,0)是干嘛的?
//它是用來對隊列任務進行一個優先級處理
//現在這個東西可以忽略不計
//當然有三個級別
//2:是是最高級別0:正常級別-2:最低級別
});同步函數的特性就是不會建立新線程,所以不會創建新線程會依次處理完
在隊列上得所有任務,執行完畢進行一個結果返回.
>同步串行處理
>什么是串行
串行會創建一條新線程.但是會依次對任務進行一個操作處理
dispatch_sync(dispatch_queue_create(nil,DISPATCH_QUEUE_SERIAL),^{
});
其實串行隊列和同步函數的是相同的原理,所以同步串行其實沒什么用,但是也會用得到,比如控制程序在手機上面的用電量,多開線程耗電會增加,如果有這個需求可以使用同步串行
>異步函數
異步函數就是會并發執行,執行完成一個返回一個是無序的,具有開啟新線程的功能
>只在主線程操作
dispatch_async(dispatch_get_main_queue()^{
})在主線程都是依次操作
>異步并發處理
dispatch_async(dispatch_get_glodal_queue(0,0),^{
});
異步并發:
1.多個任務在多條線程下同時進行
2.沒有排隊,無序,這樣容易導致出錯
>異步串行處理
dispatch_async(dispatch_queue_create(nil,DISPATCH_QUEUE_SERIAL),^{
});
異步串行:
1.多個任務在多條線程下同時進行
2.有序排隊,等每一條有執行完在進行下一個任務的操作
同步操作/異步操作總結:
1.無論是異步同步在主線程上都是依次執行
2.同步操作會依次進行操作,異步操作則是無序執行
3.同步操作不會開啟新線程,異步操作會開啟新線程
4.異步并發容易出錯,無序不排隊,會導致數據丟失
5.異步串行,安全有序
6.同步并發,限制線程開啟,但是依次執行
7.同步串行,其實兩個作用都是相同的,但是由于同步不具備開啟線程,所以還是依次執行,特殊情況下課考慮使用
并發隊列的開啟:
GCD默認已經提供了全局的并發隊列,供整個應用使用,不需要手動創建
使用dispatch_get_global_queue函數獲得全局的并發隊列
dispatch_queue_tdispatch_get_global_queue(
dispatch_queue_priority_tpriority,//隊列的優先級
unsignedlongflags);//此參數暫時無用,用0即可
dispatch_queue_tqueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);//獲得全局隊列
全局并發隊列的優先級
#define DISPATCH_QUEUE_PRIORITY_HIGH2//高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT0//默認(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)//低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN//后臺
串行隊列的創建:
GCD中獲得串行有2種途徑
使用dispatch_queue_create函數創建串行隊列
dispatch_queue_t
dispatch_queue_create(constchar*label,//隊列名稱
dispatch_queue_attr_tattr);//隊列屬性,一般用NULL即可
dispatch_queue_tqueue =dispatch_queue_create("cn.itcast.queue",NULL);//創建
dispatch_release(queue);//非ARC需要釋放手動創建的隊列
使用主隊列(跟主線程相關聯的隊列)
主隊列是GCD自帶的一種特殊的串行隊列
放在主隊列中的任務,都會放到主線程中執行
使用dispatch_get_main_queue()獲得主隊列
dispatch_queue_tqueue =dispatch_get_main_queue();
延時執行:
iOS常見的延時執行有2種方式
1>調用NSObject的方法
[selfperformSelector:@selector(run)withObject:nilafterDelay:2.0];
// 2秒后再調用self的run方法
2>使用GCD函數
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
// 2秒后執行這里的代碼...在哪個線程執行,跟隊列類型有關
});
GCD使用的在單例對象
//一次性代碼,(單例的創建)
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
//在這里創建只需要所一個的對象和對象屬性的配置信息
});
GCD中隊列組的使用
//隊列組的使用
dispatch_group_tgroup =dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//執行一個耗時操作
});
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//執行另外一個耗時操作
});
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
//回到主線程執行的操作
});
GCD中兩個特殊的隊列
//創建主隊列
dispatch_queue_tmainQueue =dispatch_get_main_queue();
//創建全局并發隊列
dispatch_queue_tglobalQueue =dispatch_get_global_queue(0,0);
GCD使用有兩個步驟:
1>將任務添加到隊列中;
2>選擇同步還是異步的方式執行任務.