-----------進(jìn)程和線程------------
- 1:進(jìn)程
- 1.1:系統(tǒng)中正在運(yùn)行的程序,稱為一個(gè)進(jìn)行
- 1.2:每個(gè)進(jìn)程,都在自己獨(dú)立的內(nèi)存空間運(yùn)行,并且進(jìn)程之間互不影響
- 2:線程
- 2.1:進(jìn)程的所有任務(wù),都是在線程執(zhí)行的,可以說它是進(jìn)程的基本執(zhí)行單元
- 2.2:進(jìn)程的串行.
2.2.1:單個(gè)進(jìn)程中執(zhí)行的任務(wù)是串行的,每個(gè)任務(wù)都是按順序執(zhí)行的
2.2.2:單個(gè)線程,同一時(shí)間內(nèi),只能執(zhí)行一個(gè)任務(wù)
- 3:進(jìn)程和線程的比較
- 3.1:進(jìn)程:
3.1.1:進(jìn)程是CPU分配資源和調(diào)度的單位
3.1.2:同一個(gè)進(jìn)程中的線程,共享該進(jìn)程下的資源
- 3.2:線程
3.2.1:線程是CPU調(diào)用(執(zhí)行任務(wù))的最小單位
3.2.2:一個(gè)進(jìn)程可以有多個(gè)線程
- 3.1:進(jìn)程:
--------------多線程--------------
- 1:概念:一個(gè)進(jìn)程可以由多個(gè)線程,每個(gè)線程可以并發(fā)執(zhí)行不同的任務(wù)(eg: 下載一個(gè)軟件,可以使用3個(gè)線程同時(shí)下載不同的文件)
- 2:原理:
- 2.1:同一時(shí)間,CPU只能調(diào)用一條線程,也就是說,同一時(shí)間只有一條線程在工作(時(shí)間極短)
- 2.2:并行,就是CPU(特指單核)以最快的速度,在不同線程之間進(jìn)行切換,調(diào)度,從而造成了并行的假象
- 2.3:多核CPU,每個(gè)核都可以同時(shí)處理不同任務(wù),從而真正達(dá)到了多線程并發(fā)執(zhí)行任務(wù)
- 3:多線程優(yōu)缺點(diǎn):
- 3.1:優(yōu)點(diǎn):
- 3.1.1:提高程序運(yùn)行效率
- 3.1.2:提高了資源利用率,充分使用了空間的內(nèi)存和CPU資源
- 3.2:缺點(diǎn):
- 3.2.1:每創(chuàng)建一條線程,都會(huì)開辟新的內(nèi)存空間,并且消耗大約90毫秒的時(shí)間
- 3.2.2:如果創(chuàng)建過多的線程,勢必會(huì)拖慢CPU的運(yùn)行速度,降低程序性能,讓CPU開銷過大
- 3.2.3:多線程設(shè)計(jì)上往往有些困難,線程間的切換,主線程子線程的協(xié)調(diào),都是開發(fā)中較難解決的問題
- 3.1:優(yōu)點(diǎn):
------多線程在iOS開發(fā)中的應(yīng)用-------
- 1:主線程
- 1.1:在應(yīng)用程序啟動(dòng)之后,在UIApplication中會(huì)自動(dòng)開啟一條主線程(UI線程)
- 1.2:主線程的作用,主要是用來顯示刷新UI界面,處理UI事件
- 2,使用時(shí)的注意事項(xiàng)
- 2.1:耗時(shí)的操作(加載時(shí)間過長的操作),不要放在主線程里,否則會(huì)影響主線程處理UI事件,導(dǎo)致運(yùn)行界面拖慢,降低用戶體驗(yàn)
- 2.2:當(dāng)耗時(shí)操作還沒有結(jié)束時(shí),UI界面無法響應(yīng)用戶的交互,直到耗時(shí)操作結(jié)束后,主線程才能繼續(xù)處理UI事件
- 2.3:因此:耗時(shí)操作,應(yīng)該放在子線程中執(zhí)行(例如后臺(tái)線程)
iOS多線程實(shí)現(xiàn)種類###
NSPerformSelector
** NSThread**:優(yōu)點(diǎn):輕量級(jí)的多線程. 缺點(diǎn):需要自己管理線程的生命周期,線程同步
- (void)viewDidLoad {
[super viewDidLoad];
//開辟子線程的方法
#pragma mark-----1,使用NSPerformSelector開辟子線程(在后臺(tái)執(zhí)行某個(gè)方法)-----
/*
performSelectorInBackground:@selector(SayHi:) withObject:@"dfklr"
參數(shù)1:需要使用子線程執(zhí)行的方法
參數(shù)2:傳遞的參數(shù)
*/
[self performSelectorInBackground:@selector(SayHi:) withObject:@"dfklr"];
#pragma mark----2.使用NSThread手動(dòng)開辟子線程------
//創(chuàng)建線程(NSThread)
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(SayHi:) object:nil];
//開啟線程
[thread start];
//關(guān)閉線程(可寫可不寫);
[NSThread exit];
// //取消線程(實(shí)際上就是做了個(gè)標(biāo)記,表示被取消)
[thread cancel];
#pragma mark----3.使用NSThread自動(dòng)開辟子線程(無需手動(dòng))-----
//延時(shí)方法
[NSThread sleepForTimeInterval:3];
[NSThread detachNewThreadSelector:@selector(SayHi:) toTarget:self withObject:@"i++"];
}
- (void)SayHi:(NSString *)str
//為保證對(duì)象及時(shí)釋放,在手動(dòng)創(chuàng)建多線程方法中需要添加自動(dòng)釋放池
@autoreleasepool {
NSLog(@"------------------嗨,girl%@",str);
NSLog(@"mianThread = %@",[NSThread mainThread]);
NSLog(@"currentThread= %@",[NSThread currentThread]);
//使用NSObject回到主線程
/*
performSelectorOnMainThread:<#(nonnull SEL)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>
參數(shù)1:回到主線程之后需要做的事情
參數(shù)2:傳遞的參數(shù)
參數(shù)3:判斷方法是否執(zhí)行完畢
YES:先執(zhí)行方法,再回到該函數(shù),執(zhí)行該函數(shù)后面的函數(shù)
*/
NSLog(@"before");
[self performSelectorOnMainThread:@selector(onMainThread) withObject:nil waitUntilDone:YES];
NSLog(@"after");
}
}
- (void)onMainThread{
NSLog(@"callBack");
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"%d",[NSThread isMainThread]);
}
NSOperationQueue和NSOperation
- 1.NSOperation
- 1.1:首先它是一個(gè)抽象類,所以執(zhí)行任務(wù)的是它的子類:NSInvocationOperation和NSBlockOperation,這兩個(gè)子類,相當(dāng)于一個(gè)方法選擇器"prefromSelector()",由它倆本身發(fā)起的任務(wù),并不是在子線程中執(zhí)行
- 1.2:NSOperation和它子類,本身并不會(huì)進(jìn)行線程的創(chuàng)建,所以,在他們的任務(wù)方法中打印當(dāng)前線程,顯示的為主線程
- 1.3:NSOperation和它的子類,只是一個(gè)操作,和多線程沒有關(guān)系,本身沒有主線程,子線程之分,可以在任何線程中使用,通常和NSOperationQueue結(jié)合使用
- 2:NSOperationQueue
一個(gè)NSOperationQueue操作隊(duì)列,就相當(dāng)于一個(gè)線程管理器,將NSOperation和子類的對(duì)象放入隊(duì)列中,然后由隊(duì)列負(fù)責(zé)派發(fā)任務(wù),所以NSOperationQueue并不是一個(gè)線程,但是,你可以設(shè)置隊(duì)列中運(yùn)行的線程的數(shù)量
優(yōu)點(diǎn):
不需要手動(dòng)關(guān)聯(lián)線程,只需要把精力放在自己要執(zhí)行的操作上面
缺點(diǎn):
它是基于OC對(duì)象的,那么相對(duì)于基于C函數(shù)來說,效率要低于GCD,GCD提供的功能比他更全面
- (void)viewDidLoad {
[super viewDidLoad];
//子類1:NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(haha) object:nil];
//operation在單獨(dú)使用的時(shí)候需要手動(dòng)調(diào)用開啟方法
// [operation start];
//子類2:NSBlockOperation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block:%@",[NSThread currentThread]);
NSLog(@"block:%@",[NSThread mainThread]);
NSLog(@"block:%d",[NSThread isMainThread]);
}];
//開啟
// [blockOperation start];
// NSOperationQueue創(chuàng)建多線程
// 如果搭配了NSOperationQueue中的add方法創(chuàng)建多線程的話,就不需要使用Start方法,否則會(huì)崩潰.
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue= [[NSOperationQueue alloc]init];
//設(shè)置最大并發(fā)數(shù)
/*
當(dāng)設(shè)置最大并發(fā)數(shù)為1時(shí),執(zhí)行順序也為串行
當(dāng)設(shè)置最大并發(fā)數(shù)大于1時(shí),叫并行,多條通道同時(shí)進(jìn)行各自的任務(wù),互不影響
*/
queue.maxConcurrentOperationCount = 1;
//給隊(duì)列添加對(duì)象
[queue addOperation:operation];
[queue addOperation:blockOperation];
}
- (void)haha{
NSLog(@"haha:%@",[NSThread currentThread]);
NSLog(@"haha:%@",[NSThread mainThread]);
NSLog(@"haha:%d",[NSThread isMainThread]);
}
GCD
- 1:特點(diǎn):
- 1.1:純C語言編寫,所以在使用的時(shí)候,使用的是函數(shù)而不是方法
- 1.2:GCD可以充分利用多核硬件并發(fā)處理多個(gè)任務(wù),提高效率
- 1.3:GCD使用后,不用程序去管理線程的開閉,GCD會(huì)在系統(tǒng)層上面動(dòng)態(tài)的檢測系統(tǒng)狀態(tài),開閉線程
- 1.4:管理線程的生命周期(調(diào)度任務(wù),銷毀線程,創(chuàng)建線程)
- 2:核心概念:
- 2.1:任務(wù):執(zhí)行什么操作
- 2.2:隊(duì)列:用來存放任務(wù)
- 3.使用GCD的兩個(gè)步驟
- 3.1:定制任務(wù):確定需要做什么事情
- 3.2:將任務(wù)添加到隊(duì)列中
- 3.2.1:GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出,放到對(duì)應(yīng)的線程中
- 3.2.2:而任務(wù)的取出,遵循隊(duì)列的先進(jìn)先出(FIFO)原則
- 4.隊(duì)列
- 4.1:并發(fā)隊(duì)列
- 4.1.1:可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟了多個(gè)線程,同時(shí)執(zhí)行任務(wù))
- 4.1.2并發(fā)功能只能在異步函數(shù)下才會(huì)有效
- 4.2:串行隊(duì)列:讓任務(wù)一個(gè)接一個(gè)執(zhí)行(一個(gè)完成,執(zhí)行下一個(gè))
- 4.3:并發(fā)和串行,決定了任務(wù)的執(zhí)行方式
- 4.3.1并發(fā):多個(gè)任務(wù)同時(shí)執(zhí)行
- 4.3.2串行:多個(gè)任務(wù)挨個(gè)執(zhí)行
#pragma mark----隊(duì)列-------
- (void)queue{
//創(chuàng)建串行隊(duì)列
dispatch_queue_t queue2 = dispatch_queue_create("queue2", 0);
//將任務(wù)添加到隊(duì)列當(dāng)中
//串行隊(duì)列+同步任務(wù)
/*
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"串行加同步%@",[NSThread currentThread]);
});
線程鎖死:
原因: 1:dispatch_sync在等待任務(wù)執(zhí)行完成,但是任務(wù)又被添加到主線程里,在主線程里執(zhí)行,所以 dispatch_sync如果在主線程調(diào)用,就會(huì)造成鎖死
2:dispatch_sync是同步的,本身就會(huì)阻塞線程,就是主線程,而現(xiàn)在又往主線程添加任務(wù),就會(huì)被發(fā)送鎖死.如上
*/
dispatch_sync(queue2, ^{
NSLog(@"串行加同步%@",[NSThread currentThread]);
});
#pragma mark---創(chuàng)建并發(fā)隊(duì)列的兩種方式-----
//第一種:系統(tǒng)方法創(chuàng)建并發(fā)隊(duì)列(全局隊(duì)列)
/*
dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>)
參數(shù)1:優(yōu)先級(jí)(有4個(gè))
參數(shù)2:系統(tǒng)保留關(guān)鍵字,暫時(shí)寫0
*/
dispatch_queue_t queues = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
//第二種:
dispatch_queue_t queuem = dispatch_queue_create("queuem", DISPATCH_QUEUE_CONCURRENT);
//并發(fā)+同步任務(wù)
dispatch_sync(queues, ^{
NSLog(@"并發(fā)+同步%@",[NSThread currentThread]);
});
//并發(fā)+異步任務(wù)(可以開啟子線程)
dispatch_async(queuem, ^{
NSLog(@"并發(fā)+異步%@",[NSThread currentThread]);
});
}
#pragma mark----Sleep------
/*
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(<#NSString * _Nonnull format, ...#>)
});
參數(shù)1:計(jì)算時(shí)間(從現(xiàn)在開始計(jì)時(shí),(int64_t)(真正延遲的時(shí)間 *NSEC_PER_SEC))
參數(shù)2:任務(wù)
*/
- (void)sleep{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"已經(jīng)3秒");
});
}
#pragma mark----向隊(duì)列中重復(fù)添加任務(wù)---------
- (void)reAdd{
//創(chuàng)建隊(duì)列
dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
/*
dispatch_apply(<#size_t iterations#>, <#dispatch_queue_t queue#>, <#^(size_t)block#>)
參數(shù)1:添加的次數(shù)
參數(shù)2:隊(duì)列
參數(shù)3:任務(wù)
*/
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"index_%zu",index);
});
}
#pragma mark----分組-----
- (void)group{
//創(chuàng)建分組
dispatch_group_t group = dispatch_group_create();
//創(chuàng)建一個(gè)并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//先分組添加任務(wù)
dispatch_group_async(group, queue, ^{
NSLog(@"我是1");
});
//用來監(jiān)聽組內(nèi)任務(wù),當(dāng)組內(nèi)任務(wù)全部執(zhí)行完畢后,才執(zhí)行此函數(shù)(組內(nèi)必須現(xiàn)有任務(wù),才可監(jiān)聽)
dispatch_group_notify(group, queue, ^{
NSLog(@"我是最后一個(gè)");
});
dispatch_group_async(group, queue, ^{
NSLog(@"我是2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"我是3");
});
}
#pragma mark---并發(fā)中的串行-----
- (void)heid{
//創(chuàng)建串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", 0);
//在串行隊(duì)列中創(chuàng)建異步任務(wù)(開辟新線程,執(zhí)行任務(wù))
dispatch_async(queue, ^{
NSLog(@"我是查詢1%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"我是查詢2%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"我是查詢3%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"我是查詢4%@",[NSThread currentThread]);
});
}
#pragma mark---應(yīng)用----
- (void)GCDuser{
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.baidu.com"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
//解析
//回到主線程刷新表格
dispatch_async(dispatch_get_main_queue(), ^{
//刷新UI
//[self.tableView reloadData];
});
}
}];
[task resume];
}
此外補(bǔ)充一點(diǎn)單例上的線程問題
static MyHandel *myhandle = nil ;
//如果在兩個(gè)并發(fā)進(jìn)程中同時(shí)走這個(gè)初始化方法時(shí),就會(huì)被初始化兩次,也就違背了單例的特征(整個(gè)應(yīng)用中,只初始化一次)
+(MyHandel *)sharehandle{
//不僅僅意味著代碼只運(yùn)行一次,而且還是線程安全的
static dispatch_once_t once;
//表示同一時(shí)間內(nèi),只有一個(gè)線程,可以訪問block里的內(nèi)容
dispatch_once(&once, ^{
myhandle = [[MyHandel alloc]init];
});
return myhandle;
}