day6---多線程

  1. 進(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時間。
  2. 串行和并行
    ??當(dāng)一個線程執(zhí)行多個任務(wù),會采用執(zhí)行完一個再執(zhí)行下一個的方式,這種執(zhí)行任務(wù)的方式稱為串行;多個線程分擔(dān)多個任務(wù),不同的任務(wù)同時執(zhí)行,這種執(zhí)行任務(wù)的方式稱為并發(fā)。
  3. 同步和異步
    ??同步是指當(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");
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容