多線程(NSThread)

線程與進程的關系:

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>選擇同步還是異步的方式執行任務.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容