多線(xiàn)程

多線(xiàn)程原理:

  • 同一時(shí)間CPU只能處理一條線(xiàn)程, 只有一條線(xiàn)程在工作
  • 多線(xiàn)程并發(fā)執(zhí)行,起始是CPU在各個(gè)線(xiàn)程之間快速調(diào)度的結(jié)果
  • 由于CPU調(diào)度線(xiàn)程速度非???,所以就造成了多線(xiàn)程并發(fā)的假象

一般情況下耗時(shí)操作放在子線(xiàn)程里面,多線(xiàn)程也正是解決耗時(shí)操作,防止卡住主線(xiàn)程產(chǎn)生的。

主線(xiàn)程

  • 程序已啟動(dòng)就自動(dòng)創(chuàng)建的線(xiàn)程就是主線(xiàn)程
  • 作用一般就是相應(yīng)用戶(hù)點(diǎn)擊事件,刷新UI等等

多線(xiàn)程的實(shí)現(xiàn)方案

Paste_Image.png
  • NSThread
@Parmark 第一中創(chuàng)建方法
    //創(chuàng)建線(xiàn)程
    //在內(nèi)存中開(kāi)辟空間
    NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"thread"];
    thread.name = @"my-thread";
    //啟動(dòng)線(xiàn)程  并且系統(tǒng)會(huì)把這個(gè)線(xiàn)程放到可調(diào)度程序池里面 為了方便CPU來(lái)回調(diào)用
    [thread start];

//任務(wù)執(zhí)行完畢后 會(huì)自動(dòng)銷(xiāo)毀線(xiàn)程
- (void)run:(NSString *)param
{
    //處理耗時(shí)操作
}

@Parmark 第二中創(chuàng)建方法

[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"thread"];

- (void)run:(NSString *)param
{
    //處理耗時(shí)操作
}

@Parmark 第三中創(chuàng)建方法

[self performSelectorInBackground:@selector(run:) withObject:@"thread"];

- (void)run:(NSString *)param
{
    //處理耗時(shí)操作
}


 //卡住線(xiàn)程睡兩秒 控制線(xiàn)程進(jìn)入阻塞狀態(tài)
[NSThread sleepForTimeInterval:2.0];


//退出線(xiàn)程(強(qiáng)制性的)
[NSThread exit];

線(xiàn)程安全

  • 資源共享:一塊資源 被多個(gè)線(xiàn)程共享 也就是多個(gè)線(xiàn)程訪(fǎng)問(wèn)同一塊資源

隱患:

Paste_Image.png

解決引號(hào) -- > 加把互斥鎖

Paste_Image.png

代碼:

###沒(méi)加互斥鎖的代碼

    self.ticketCount = 100;//100張票
    
    self.thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread1.name = @"售票員1";
    
    self.thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread2.name = @"售票員2";
    
    self.thread3 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread3.name = @"售票員3";

- (void)saleTicket
{
    while (1) {
        //先取出總數(shù)
        NSInteger count = self.ticketCount;
        if (count > 0) {
            
            self.ticketCount = count - 1;
            
            NSLog(@"%@賣(mài)了一張票 -- 還剩下%ld張票",[NSThread currentThread].name,_ticketCount);
        }else{
            NSLog(@"票已經(jīng)賣(mài)完了");
            break;
        }
    }
}
###加互斥鎖的代碼
- (void)saleTicket
{
    //用同一把鎖 可以記錄線(xiàn)程的狀態(tài)
    while (1) {
        
        @synchronized (self) {//加鎖
            
            //先取出總數(shù)
            NSInteger count = self.ticketCount;
            if (count > 0) {
                
                self.ticketCount = count - 1;
                
                NSLog(@"%@賣(mài)了一張票 -- 還剩下%ld張票",[NSThread currentThread].name,_ticketCount);
            }else{
                NSLog(@"票已經(jīng)賣(mài)完了");
                break;
            }
        }
        
    }
}

線(xiàn)程間的通訊


//開(kāi)辟一個(gè)子線(xiàn)程
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelectorInBackground:@selector(downLoad) withObject:nil];
}


//子線(xiàn)程要做的事
- (void)downLoad
{
    NSURL * url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/5ab5c9ea15ce36d358d27ee43ef33a87e850b114.jpg"];
    
    //下載圖片
    NSData * data = [NSData dataWithContentsOfURL:url];
    
    //生成圖片
    UIImage * image = [UIImage imageWithData:data];
    
    //回到主線(xiàn)程刷新UI
    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
    
//    [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];

}

GCD的基本使用

  • 任務(wù): 執(zhí)行操作
  • 隊(duì)列: 存放任務(wù)
    • 隊(duì)列的類(lèi)型
    • 并發(fā)隊(duì)列 (只有在)dispatch_async下才有效
    • 串行隊(duì)列

同步 - 異步:主要影響是能不能開(kāi)新線(xiàn)程

  • 同步只能在當(dāng)前線(xiàn)程執(zhí)行任務(wù),不能開(kāi)啟新線(xiàn)程
  • 異步可以在新的線(xiàn)程中執(zhí)行任務(wù),能開(kāi)啟新線(xiàn)程

串行 - 并發(fā):主要影響任務(wù)的執(zhí)行方式

  • 串行:一個(gè)任務(wù)執(zhí)行完畢 執(zhí)行下一個(gè)任務(wù)
  • 并發(fā):多個(gè)任務(wù)同時(shí)執(zhí)行

使用步驟

  • 定制任務(wù):確定想要做的事情
  • 將任務(wù)添加到隊(duì)列中
    • GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出來(lái),放到對(duì)應(yīng)的線(xiàn)程中執(zhí)行
    • 任務(wù)的去除遵循:先進(jìn)先出 后進(jìn)后出 的原則

代碼:


//異步線(xiàn)程
    dispatch_async(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
    //同步線(xiàn)程
    dispatch_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)

###異步函數(shù)+并發(fā)隊(duì)列 (可以開(kāi)啟多條線(xiàn)程 并且可以同時(shí)執(zhí)行)
//創(chuàng)建一個(gè)并發(fā)隊(duì)列  DISPATCH_QUEUE_CONCURRENT:隊(duì)列類(lèi)型
    dispatch_queue_t queue = dispatch_queue_create("com.baidu.queue", DISPATCH_QUEUE_CONCURRENT);
    
    //將任務(wù)加入隊(duì)列
    dispatch_async(queue, ^{
       
        NSLog(@"%@",[NSThread currentThread]);
        
    });

#@pargam 或者這種寫(xiě)法

//獲取全局隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //將任務(wù)加入隊(duì)列
    dispatch_async(queue, ^{
       
        NSLog(@"%@",[NSThread currentThread]);
        
    });


###同步函數(shù)+并發(fā)隊(duì)列 (不會(huì)開(kāi)啟新的線(xiàn)程)

//獲得全局的并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //同步函數(shù)
    dispatch_sync(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });


###異步函數(shù)+串行對(duì)列 (可以開(kāi)線(xiàn)程 但是不能同時(shí)執(zhí)行)
//串行隊(duì)列 沒(méi)有全局的 只能手動(dòng)創(chuàng)建
    dispatch_queue_t queue = dispatch_queue_create("com.baidu.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });

###同步函數(shù)+串行對(duì)列 (不可以開(kāi)線(xiàn)程 )

 //串行隊(duì)列 沒(méi)有全局的 只能手動(dòng)創(chuàng)建
    dispatch_queue_t queue = dispatch_queue_create("com.baidu.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });

主隊(duì)列

  • GCD自帶的一種特殊的串行隊(duì)列
  • 放到主隊(duì)列的任務(wù)都會(huì),在主線(xiàn)程中執(zhí)行
  • 使用dispatch_get_main_queue()獲取主隊(duì)列

###主隊(duì)列+異步函數(shù)(只會(huì)在主線(xiàn)程中執(zhí)行任務(wù))

dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        
        NSLog(@"%@",[NSThread currentThread]);
        
    });

###主隊(duì)列+同步函數(shù)(線(xiàn)程沖突 不會(huì)執(zhí)行任何操作)

dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_sync(queue, ^{
        
        NSLog(@"%@",[NSThread currentThread]);
        
    });

各種隊(duì)列的執(zhí)行效果

Paste_Image.png

GCD的線(xiàn)程之間通訊


dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        NSURL * url = [NSURL URLWithString:@"https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1479864304&di=99dcf40127f2dc4273536f73d0951638&src=http://d.hiphotos.baidu.com/image/pic/item/2e2eb9389b504fc2065e2bd2e1dde71191ef6de0.jpg"];
        NSData * data = [NSData dataWithContentsOfURL:url];
        
        UIImage * image = [UIImage imageWithData:data];
        
        //回到主線(xiàn)程
        dispatch_async(dispatch_get_main_queue(), ^{
           
            self.imageView.image = image;
            
        });
        
    });

GCD中還有另外一個(gè)執(zhí)行任務(wù)的函數(shù)

//在它前面的函數(shù)執(zhí)行完畢才執(zhí)行它的任務(wù),在它后面的函數(shù)在它執(zhí)行完畢后才開(kāi)始執(zhí)行
dispatch_barrier_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)

iOS延時(shí)執(zhí)行的函數(shù)

//延時(shí)兩秒執(zhí)行run方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];


dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //執(zhí)行的操作
        
    });

[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];


static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //一次性函數(shù)
        //此函數(shù)只執(zhí)行一次
    });

GCD隊(duì)列組

  • 用隊(duì)列組下載多張圖片并且合成一張圖片

//創(chuàng)建一個(gè)隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //創(chuàng)建一個(gè)隊(duì)列組
    dispatch_group_t group = dispatch_group_create();
    
    //1.下載圖片1
    dispatch_group_async(group, queue, ^{
        
        NSURL * url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/h%3D200/sign=4241e02c86025aafcc3279cbcbecab8d/562c11dfa9ec8a13f075f10cf303918fa1ecc0eb.jpg"];
        NSData * data = [NSData dataWithContentsOfURL:url];
        
        UIImage * image = [UIImage imageWithData:data];
        
        self.image1 = image;
        
        
    });
    //2.下載圖片2
    dispatch_group_async(group, queue, ^{
        
        
        NSURL * url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/pic/item/8cb1cb134954092359d94e479758d109b3de4952.jpg"];
        NSData * data = [NSData dataWithContentsOfURL:url];
        
        UIImage * image = [UIImage imageWithData:data];
        
        self.image2 = image;
        
        
    });
    //3.將圖片1和圖片2合成一張新的圖片
    dispatch_group_notify(group, queue, ^{
        //能保證組里面的任務(wù)都完成了
        //能來(lái)到這里說(shuō)明前兩張圖片一定下載完了
        
        //開(kāi)啟圖形上下文
        UIGraphicsBeginImageContext(CGSizeMake(336, 440));
        
        //繪制圖片
        [self.image1 drawInRect:CGRectMake(0, 0, 168, 220)];
        [self.image2 drawInRect:CGRectMake(168, 0, 168, 220)];
        
        //獲取上下文的圖片
        UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
        
        //結(jié)束上下文
        UIGraphicsEndImageContext();
        
        //回到主線(xiàn)程顯示圖片
        dispatch_async(dispatch_get_main_queue(), ^{
           
            self.imageView.image = image;
            
        });
        
        
    });
    //4.將合成后的圖片顯示出來(lái)

GCD實(shí)現(xiàn)單利

###第一種方式

static Person * _person;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone: zone];
    });
    return _instance;
}

+ (instancetype)defaultManger
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        _person = [[self alloc]init];
        
    });
    return _person;
}


//記得遵守NSCopying協(xié)議
//實(shí)現(xiàn)此方法為了保證copy的時(shí)候  訪(fǎng)問(wèn)的是同一個(gè)對(duì)象
- (id)copyWithZone:(NSZone *)zone
{
    return _person;
}


###第二種方式

static id _instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    @synchronized (self) {//加鎖 防止多線(xiàn)程訪(fǎng)問(wèn)出問(wèn)題
        if (_instance == nil)
        {
            _instance = [self allocWithZone:zone];
        }
    }
    return _instance;
}

+ (instancetype)sharedInstance
{
    @synchronized (self) {//加鎖 防止多線(xiàn)程訪(fǎng)問(wèn)出問(wèn)題
        if (_instance == nil)
        {
            _instance = [[self alloc]init];
        }
    }
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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