- 進(jìn)程和線程
??進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個數(shù)據(jù)集合上的一次運(yùn)行活動,是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的一個獨(dú)立單位;線程是進(jìn)程的一個實(shí)體,是CPU調(diào)度和分派的基本單位,是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。線程的劃分尺度小于進(jìn)程,這使得多線程程序的并發(fā)性高;進(jìn)程在執(zhí)行時通常擁有獨(dú)立的內(nèi)存單元,而線程之間可以共享內(nèi)存。使用多線程的編程通常能夠帶來更好的性能和用戶體驗(yàn),但是多線程的程序?qū)τ谄渌绦蚴遣挥押玫?,因?yàn)樗赡苷加昧烁嗟腃PU資源。當(dāng)然,也不是線程越多,程序的性能就越好,因?yàn)榫€程之間的調(diào)度和切換也會浪費(fèi)CPU時間。 - 串行和并行
??當(dāng)一個線程執(zhí)行多個任務(wù),會采用執(zhí)行完一個再執(zhí)行下一個的方式,這種執(zhí)行任務(wù)的方式稱為串行;多個線程分擔(dān)多個任務(wù),不同的任務(wù)同時執(zhí)行,這種執(zhí)行任務(wù)的方式稱為并發(fā)。 - 同步和異步
??同步是指當(dāng)前一個任務(wù)未能完成時,后一個任務(wù)被阻塞;異步可以理解為不同的任務(wù)在不同的線程中執(zhí)行,當(dāng)開辟的子線程(工作線程)發(fā)生阻塞,主線程或其他線程不會受到影響。
說明:異步和并發(fā)的概念不完全相同,異步強(qiáng)調(diào)解決主線程阻塞的問題,而并發(fā)一般指子線程(工作線程)之間的關(guān)系,多個工作線程分擔(dān)任務(wù)稱為并發(fā)執(zhí)行任務(wù)。
??iOS開發(fā)中實(shí)現(xiàn)多線程的方式很多,包括:
- NSThread類:線程,此種方式是輕量級的線程機(jī)制,但需要自行管理線程的生命周期,線程同步等問題,同步鎖會產(chǎn)生系統(tǒng)開銷。
-
NSThread類:
線程,此種方式是輕量級的線程機(jī)制,但需要自行管理線程的生命周期,線程同步等問題,同步鎖會產(chǎn)生系統(tǒng)開銷。1.創(chuàng)建線程的三種方式:
//第一種創(chuàng)建方法
//第一個參數(shù) 執(zhí)行線程的對象
//第二個參數(shù) 選擇器
//第三個參數(shù) 傳入的參數(shù)
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
//標(biāo)記執(zhí)行某一線程任務(wù)時的線程名字
thread.name = @"線程1";
//開啟線程
[thread start];//第二種方法:類方法創(chuàng)建 【不返回任何數(shù)據(jù)類型】
[NSThread detachNewThreadSelector:@selector(run1:) toTarget:self withObject:@"33333"];//第三種方法:創(chuàng)建一個在后臺的線程
[self performSelectorInBackground:@selector(run2) withObject:nil];
2.給線程加鎖的三種方式
1)lock三個步驟:
//第一步:初始化一個鎖的對象;
//鎖是為了保障訪問同一數(shù)據(jù)時 數(shù)據(jù)的安全性
_lock = [[NSLock alloc] init];
//第二步:給子線程加鎖,不允許其它線程訪問;
[_lock lock];
//第三部:子線程結(jié)束,給子線程解鎖;允許其它線程訪問;
[_lock unlock];
2)sychronized方法: 【將子線程要執(zhí)行的操作寫在大括號中】
//nonatomic非原子性 atomic 原子性(對同一時間訪問的對象進(jìn)行保護(hù))
//相比于lock 而言,它只能鎖住一次,不能重復(fù)加鎖
//一旦鎖住則知道線程完畢才允許另一個線程訪問
@synchronized (self) 【這個方法直接寫在子線程的實(shí)現(xiàn)方法中】
{
}
3)condition方法三個步驟:【和lock類似,但是多了暫停功能】
初始化
_condition = [[NSCondition alloc] init];
上鎖
//condition上鎖和lock相似
[_condition lock];
解鎖
[_condition unlock];
condition的暫停功能:
//暫停判斷,程序一進(jìn)來就做判斷;
if (_tickets == 90) 【給暫停條件】
{
//暫停
[_condition wait];
}
【什么時候解除暫?!?
[self performSelector:@selector(until) withObject:nil afterDelay:3];
-(void)until
{
//喚醒線程
[_condition signal];
}
3.子線程給主線程傳值的兩種方法: 【系統(tǒng)自帶的方法】
//************ 給主線程傳數(shù)據(jù) ****************,
//方法一
//第一個參數(shù):選擇器
//第二個參數(shù):傳參
//第三個參數(shù):等待是否執(zhí)行完畢
NSLog(@"000000000000000000000");
[self performSelectorOnMainThread:@selector(log:) withObject:@"1111111" waitUntilDone:YES];
NSLog(@"2222222222222222222222");
//方法二
[self performSelector:@selector(log:) onThread:[NSThread mainThread] withObject:@"444444" waitUntilDone:NO];
二、operation
1)創(chuàng)建operation的兩種方法
//************ 創(chuàng)建operation的兩種方式 **************
//第一個參數(shù):表示調(diào)起線程的對象
//第二個參數(shù):選擇器
//第三個參數(shù):傳入的參數(shù)
//第一種方法
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(log) object:nil];
[operation start]; 【創(chuàng)建operation對象,開啟對象】
//第二種方法
【這種方法創(chuàng)建的operation對象可以另外給線程添加任務(wù)】
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2222222222");
}];
[operation1 addExecutionBlock:^{ 【另外添加任務(wù)的方法】
//線程添加任務(wù)
NSLog(@"3333333");
}];
[operation1 start];
2)將operation對象添加到隊(duì)列中
NSOperationQueue *q = [[NSOperationQueue alloc] init]; 【創(chuàng)建隊(duì)列】
//先給依賴關(guān)系,即先排好順序;
[operation1 addDependency:operation]; 【先排序】
[operation2 addDependency:operation1];
[operation3 addDependency:operation2];
//在添加到隊(duì)列中;
[q addOperation:operation];
[q addOperation:operation1]; 【添加operation】
[q addOperation:operation2];
[q addOperation:operation3];
//最大并行數(shù) 如果設(shè)置為1 表示串行
[q setMaxConcurrentOperationCount:1];
3)用多線程申請數(shù)據(jù)
-(void)loadData
{
_imageArry = [NSMutableArray array];
NSMutableArray *qArr = [NSMutableArray array];
for (int i=0; i<_imgArr.count; i++) {
NSBlockOperation *operation = [NSBlockOperation 【創(chuàng)建多個線程】blockOperationWithBlock:^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:_imgArr[i]]]];
[_imageArry addObject:image];
if (i==_imgArr.count-1) {
【利用子線程傳值的方法回到主線程刷新數(shù)據(jù)】
[_tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
//下面這個回到主線程的方法是在reloadData刷新數(shù)據(jù)借宿后調(diào)用的
dispatch_async(dispatch_get_main_queue(), ^{
【數(shù)據(jù)刷新成功以后調(diào)用這個方法,檢測什么時候刷新結(jié)束】
NSLog(@"刷新結(jié)束");
});
}
}];
if (i>0) {
【給子線程添加依賴關(guān)系,即給子線程排序】
[operation addDependency:(NSOperation *)[qArr lastObject]];
}
[qArr addObject:operation];
}
NSOperationQueue *q = [[NSOperationQueue alloc] init];
for (int i= (int)qArr.count-1; i>=0; i--) {
[q addOperation:qArr[i]]; 【將子線程添加到隊(duì)列中】
}
[q setMaxConcurrentOperationCount:1];
}
三、GCD
3 GCD
1.什么是GCD?
全稱是Grand Central Dispatch,可譯為“牛逼的中樞調(diào)度器”
純C語言,提供了非常多強(qiáng)大的函數(shù)
2.GCD的優(yōu)勢
GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案
GCD會自動利用更多的CPU內(nèi)核(比如雙核、四核)
GCD會自動管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程)
程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼
//1.延遲執(zhí)行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// NSLog(@"11111");
});
//2.單例的創(chuàng)建
[self createManager];
-(void)createManager
{
//2.單例的創(chuàng)建
//創(chuàng)建一個執(zhí)行一次的靜態(tài)的線程
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//執(zhí)行線程
manager = [[UIViewController alloc] init];
});
NSLog(@"----------%p",manager);
}
//3.進(jìn)入異步 自動進(jìn)入ios隊(duì)列等待執(zhí)行.開辟線程做某件事
dispatch_async(dispatch_get_global_queue(0, 0), ^{
});
//回到主線程做某件事
dispatch_async(dispatch_get_main_queue(), ^{
});
//4.先在異步做某件事情,然后回到主線程再做其他事情;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//回到主線程做某件事
dispatch_async(dispatch_get_main_queue(), ^{
});
});
//5.自定義線程,創(chuàng)建一個線程;
dispatch_queue_t urlq = dispatch_queue_create("1111", NULL);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, urlq, ^{
NSLog(@"222222");
});
dispatch_group_async(group, urlq, ^{
NSLog(@"333333");
});
dispatch_group_notify(group, urlq, ^{
NSLog(@"000099999");
});
dispatch_group_async(group, urlq, ^{
NSLog(@"4444444");
});
dispatch_group_async(group, urlq, ^{
NSLog(@"5555555");
});
//下面這個代碼塊永遠(yuǎn)在一個組中最后一個執(zhí)行
dispatch_group_notify(group, urlq, ^{
NSLog(@"000066666");
});