iOS底層day9 - 多線程

進(jìn)程 & 線程

  • 提到線程捌朴,那就不得不提CPU吴攒,現(xiàn)代的CPU有一個(gè)很重要的特性,就是時(shí)間片男旗,每一個(gè)獲得CPU的任務(wù)只能運(yùn)行一個(gè)時(shí)間片規(guī)定的時(shí)間舶斧。
  • 其實(shí)線程對操作系統(tǒng)來說就是一段代碼以及運(yùn)行時(shí)數(shù)據(jù)卧波。操作系統(tǒng)會(huì)為每個(gè)線程保存相關(guān)的數(shù)據(jù)于游,當(dāng)接收到來自CPU的時(shí)間片中斷事件時(shí)涛酗,就會(huì)按一定規(guī)則從這些線程中選擇一個(gè),恢復(fù)它的運(yùn)行時(shí)數(shù)據(jù)誓焦,這樣CPU就可以繼續(xù)執(zhí)行這個(gè)線程了蠕嫁。
  • 也就是其實(shí)就單核CUP而言冰寻,并沒有辦法實(shí)現(xiàn)真正意義上的并發(fā)執(zhí)行觉阅,只是CPU快速地在多條線程之間調(diào)度,CPU調(diào)度線程的時(shí)間足夠快嗜闻,就造成了多線程并發(fā)執(zhí)行的假象蜕依。并且就單核CPU而言多線程可以解決線程阻塞的問題,但是其本身運(yùn)行效率并沒有提高琉雳,多CPU的并行運(yùn)算才真正解決了運(yùn)行效率問題样眠。
  • 系統(tǒng)中正在運(yùn)行的每一個(gè)應(yīng)用程序都是一個(gè)進(jìn)程,每個(gè)進(jìn)程系統(tǒng)都會(huì)分配給它獨(dú)立的內(nèi)存運(yùn)行翠肘。也就是說檐束,在iOS系統(tǒng)中中,每一個(gè)應(yīng)用都是一個(gè)進(jìn)程束倍。
  • 一個(gè)進(jìn)程的所有任務(wù)都在線程中進(jìn)行被丧,因此每個(gè)進(jìn)程至少要有一個(gè)線程,也就是主線程绪妹。那多線程其實(shí)就是一個(gè)進(jìn)程開啟多條線程甥桂,讓所有任務(wù)并發(fā)執(zhí)行。
  • 多線程在一定意義上實(shí)現(xiàn)了進(jìn)程內(nèi)的資源共享邮旷,以及效率的提升黄选。同時(shí),在一定程度上相對獨(dú)立廊移,它是程序執(zhí)行流的最小單元糕簿,是進(jìn)程中的一個(gè)實(shí)體,是執(zhí)行程序最基本的單元狡孔,有自己棧和寄存器

同步異步 & 串行并行

同步與異步的區(qū)別:具不具備開線程的能力
串行與并行:可不可以同時(shí)執(zhí)行多個(gè)任務(wù),異步是多個(gè)任務(wù)并行的前提條件

舉個(gè)栗子 & 同步異步

    dispatch_queue_t queue = dispatch_queue_create("myquere", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"queue4 -- %d -----%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"queue5 -- %d -----%@",i,[NSThread currentThread]);
        }
    });

打印結(jié)果

2018-11-07 08:51:58.130210+0800 09-線程[1136:19292] queue4 -- 0 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.130486+0800 09-線程[1136:19292] queue4 -- 1 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.130669+0800 09-線程[1136:19292] queue4 -- 2 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.130822+0800 09-線程[1136:19292] queue4 -- 3 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.131010+0800 09-線程[1136:19292] queue4 -- 4 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.131154+0800 09-線程[1136:19292] queue4 -- 5 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.131290+0800 09-線程[1136:19292] queue4 -- 6 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.131423+0800 09-線程[1136:19292] queue4 -- 7 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.131548+0800 09-線程[1136:19292] queue4 -- 8 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.132504+0800 09-線程[1136:19292] queue4 -- 9 -----<NSThread: 0x600000076240>{number = 1, name = main}
2018-11-07 08:51:58.133260+0800 09-線程[1136:19344] queue5 -- 0 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.133849+0800 09-線程[1136:19344] queue5 -- 1 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.174407+0800 09-線程[1136:19344] queue5 -- 2 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.174590+0800 09-線程[1136:19344] queue5 -- 3 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.175140+0800 09-線程[1136:19344] queue5 -- 4 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.175492+0800 09-線程[1136:19344] queue5 -- 5 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.176540+0800 09-線程[1136:19344] queue5 -- 6 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.176792+0800 09-線程[1136:19344] queue5 -- 7 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.176952+0800 09-線程[1136:19344] queue5 -- 8 -----<NSThread: 0x604000469880>{number = 3, name = (null)}
2018-11-07 08:51:58.177108+0800 09-線程[1136:19344] queue5 -- 9 -----<NSThread: 0x604000469880>{number = 3, name = (null)}

異步下蜂嗽,開啟了一個(gè)子線程number 3 去執(zhí)行任務(wù)

舉個(gè)栗子 & 串行并行

異步串行:

    dispatch_queue_t queue2 = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue2, ^{
            NSLog(@"queue5 -- %d -----%@",i,[NSThread currentThread]);
        });
    }

執(zhí)行結(jié)果:

2018-11-07 09:13:22.052006+0800 09-線程[2109:42825] queue5 -- 0 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.052427+0800 09-線程[2109:42825] queue5 -- 1 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.052618+0800 09-線程[2109:42825] queue5 -- 2 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.052806+0800 09-線程[2109:42825] queue5 -- 3 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.053263+0800 09-線程[2109:42825] queue5 -- 4 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.053826+0800 09-線程[2109:42825] queue5 -- 5 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.053981+0800 09-線程[2109:42825] queue5 -- 6 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.054201+0800 09-線程[2109:42825] queue5 -- 7 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.054602+0800 09-線程[2109:42825] queue5 -- 8 -----<NSThread: 0x604000467940>{number = 3, name = (null)}
2018-11-07 09:13:22.054895+0800 09-線程[2109:42825] queue5 -- 9 -----<NSThread: 0x604000467940>{number = 3, name = (null)}

異步并行:

    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue, ^{
            NSLog(@"queue6 -- %d -----%@",i,[NSThread currentThread]);
        });
    }

執(zhí)行結(jié)果:

2018-11-07 09:14:53.988564+0800 09-線程[2145:44288] queue6 -- 0 -----<NSThread: 0x600000268d00>{number = 3, name = (null)}
2018-11-07 09:14:53.988575+0800 09-線程[2145:44289] queue6 -- 3 -----<NSThread: 0x6000002687c0>{number = 6, name = (null)}
2018-11-07 09:14:53.988569+0800 09-線程[2145:44290] queue6 -- 2 -----<NSThread: 0x600000267080>{number = 5, name = (null)}
2018-11-07 09:14:53.988607+0800 09-線程[2145:44287] queue6 -- 1 -----<NSThread: 0x600000268980>{number = 4, name = (null)}
2018-11-07 09:14:53.988889+0800 09-線程[2145:44288] queue6 -- 4 -----<NSThread: 0x600000268d00>{number = 3, name = (null)}
2018-11-07 09:14:53.988926+0800 09-線程[2145:44289] queue6 -- 5 -----<NSThread: 0x6000002687c0>{number = 6, name = (null)}
2018-11-07 09:14:53.989017+0800 09-線程[2145:44314] queue6 -- 6 -----<NSThread: 0x600000267000>{number = 7, name = (null)}
2018-11-07 09:14:53.989041+0800 09-線程[2145:44315] queue6 -- 7 -----<NSThread: 0x604000274080>{number = 8, name = (null)}
2018-11-07 09:14:53.989114+0800 09-線程[2145:44316] queue6 -- 8 -----<NSThread: 0x604000273e40>{number = 10, name = (null)}
2018-11-07 09:14:53.989114+0800 09-線程[2145:44317] queue6 -- 9 -----<NSThread: 0x604000273f40>{number = 9, name = (null)}

異步并行下苗膝,開啟了多個(gè)線程去同時(shí)執(zhí)行任務(wù)

線程死鎖

先來看以下代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"1");
    });
}

這里,viewDidLoad^{ NSLog(@"1") }植旧,為兩個(gè)任務(wù)AB辱揭,首先A在主隊(duì)列,并且在主線程執(zhí)行病附,這時(shí)候主隊(duì)列加入了任務(wù)B问窃,于是主隊(duì)列的順序就是 A執(zhí)行完、執(zhí)行B完沪,我們這里又是用串行sync執(zhí)行域庇,需要block的內(nèi)容執(zhí)行完畢(B執(zhí)行完畢)嵌戈,任務(wù)A才執(zhí)行完畢,所以這里就出現(xiàn)了互相等待的死鎖情況听皿。
這里熟呛,我們可以把dispatch_get_main_queue() 換成另外一個(gè)隊(duì)列,就不會(huì)出現(xiàn)死鎖了

線程鎖

當(dāng)我們使用多線程時(shí)尉姨,操作同一個(gè)任務(wù)的時(shí)候庵朝,是有可能出現(xiàn)線程不安全的問題:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.money = 200;
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        for (int i = 0; i < 10; i ++) {
            [self saveMoney];
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 10; i ++) {
            [self drawMoney];
        }
    });
 
}

- (void)saveMoney {
    int money = self.money;
    sleep(.2);
    money += 50;
    self.money = money;
    
    NSLog(@"存錢50 - 當(dāng)前金額為:%d , 當(dāng)前線程為 %@",self.money,[NSThread currentThread]);
}

- (void)drawMoney {
    int money = self.money;
    sleep(.2);
    money -= 20;
    self.money = money;
    
    NSLog(@"取錢20 - 當(dāng)前金額為:%d , 當(dāng)前線程為 %@",self.money,[NSThread currentThread]);
}

打印結(jié)果:

2018-11-07 15:11:20.045459+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:180 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.045453+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:250 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.045730+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:230 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.045797+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:210 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.046415+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:260 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.046626+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:240 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.046797+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:290 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.046900+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:270 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.047037+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:320 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.048622+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:300 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.049292+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:350 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.049894+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:330 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.050160+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:380 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.051462+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:360 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.051761+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:410 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.052363+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:390 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.052789+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:440 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.053310+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:420 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}
2018-11-07 15:11:20.053921+0800 09-線程[4708:212475] 存錢50 - 當(dāng)前金額為:470 , 當(dāng)前線程為 <NSThread: 0x6000002770c0>{number = 3, name = (null)}
2018-11-07 15:11:20.054219+0800 09-線程[4708:212472] 取錢20 - 當(dāng)前金額為:450 , 當(dāng)前線程為 <NSThread: 0x600000276fc0>{number = 4, name = (null)}

照理說,我們進(jìn)行了10次的存錢取錢又厉,最終得到的結(jié)果應(yīng)該是500塊錢九府,可是這里卻沒有,原因是因?yàn)槲覀冊诖驽X/取錢的時(shí)候覆致,是同時(shí)進(jìn)行的侄旬,假如當(dāng)?shù)谝淮稳〕龅腻Xself.money是200,這時(shí)候進(jìn)行了存錢操作篷朵,則記錄為250勾怒,但是取錢又是同時(shí)進(jìn)行的,在存錢操作沒有做完的時(shí)候声旺,取錢操作取出的錢也是200笔链,進(jìn)行取錢操作后記錄為180,這時(shí)候無論誰把錢賦值給self.money都是錯(cuò)誤的腮猖,所以這里存錢和取錢的操作應(yīng)該是分開進(jìn)行的鉴扫,于是我們就有了線程鎖的概念。
線程鎖有很多種澈缺,包括:

  • OSSpinLock : iOS10之前的線程鎖坪创,現(xiàn)在已經(jīng)不安全了,會(huì)出現(xiàn)優(yōu)先級反轉(zhuǎn)的問題 (自旋鎖)
  • os_unfair_lock : iOS10之后替換OSSpinLock
  • pthread_mutex: 跨平臺(tái)鎖姐赡,可傳入屬性莱预,作為遞歸鎖
  • dispatch_semaphore (信號(hào)量): 控制線程的并發(fā)數(shù)量
  • NSConditionLock:線程先后執(zhí)行順序
  • @synchroized :對象鎖,傳入的同一個(gè)對象就可以實(shí)現(xiàn)同步项滑,性能較差(封裝pthread_mutex)依沮,但是用法最簡單
    …………
    性能排序

線程鎖用法

這里主要講 dispatch_semaphore、 @synchroized枪狂、NSConditionLock的用法

dispatch_semaphore

- (void)viewDidLoad {
    [super viewDidLoad];
    // 傳入的5表示控制線程最大的并發(fā)數(shù)量為5
    self.semaphore = dispatch_semaphore_create(5);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    for (int i = 0; i < 20; i++) {
        [[[NSThread alloc] initWithTarget:self selector:@selector(semaphoreTest) object:nil] start];
    }
}
- (void)semaphoreTest {
    // 如果信號(hào)量的值 > 0危喉,就讓信號(hào)量的值減1,然后繼續(xù)往下執(zhí)行代碼
    // 如果信號(hào)量的值 <= 0州疾,就會(huì)休眠等待辜限,直到信號(hào)量的值變成>0,就讓信號(hào)量的值減1严蓖,然后繼續(xù)往下執(zhí)行代碼
    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
    
    sleep(2);
    NSLog(@"test - %@", [NSThread currentThread]);
    
    // 讓信號(hào)量的值+1
    dispatch_semaphore_signal(self.semaphore);
}

打印結(jié)果:

2018-11-08 09:42:43.756944+0800 09-線程[1815:57093] test - <NSThread: 0x604000278880>{number = 4, name = (null)}
2018-11-08 09:42:43.756940+0800 09-線程[1815:57094] test - <NSThread: 0x60400026fd40>{number = 5, name = (null)}
2018-11-08 09:42:43.756937+0800 09-線程[1815:57096] test - <NSThread: 0x60400026f880>{number = 7, name = (null)}
2018-11-08 09:42:43.757042+0800 09-線程[1815:57095] test - <NSThread: 0x604000279400>{number = 6, name = (null)}
2018-11-08 09:42:43.757078+0800 09-線程[1815:57092] test - <NSThread: 0x60400026f040>{number = 3, name = (null)}
2018-11-08 09:42:45.763554+0800 09-線程[1815:57097] test - <NSThread: 0x604000270900>{number = 8, name = (null)}
2018-11-08 09:42:45.763560+0800 09-線程[1815:57099] test - <NSThread: 0x604000274000>{number = 10, name = (null)}
2018-11-08 09:42:45.763649+0800 09-線程[1815:57098] test - <NSThread: 0x604000274080>{number = 9, name = (null)}
2018-11-08 09:42:45.763702+0800 09-線程[1815:57100] test - <NSThread: 0x604000276740>{number = 11, name = (null)}
2018-11-08 09:42:45.763807+0800 09-線程[1815:57101] test - <NSThread: 0x604000274c80>{number = 12, name = (null)}
2018-11-08 09:42:47.770115+0800 09-線程[1815:57104] test - <NSThread: 0x60400026d480>{number = 15, name = (null)}
2018-11-08 09:42:47.770243+0800 09-線程[1815:57103] test - <NSThread: 0x604000278b40>{number = 14, name = (null)}
2018-11-08 09:42:47.770122+0800 09-線程[1815:57102] test - <NSThread: 0x60400026d680>{number = 13, name = (null)}
2018-11-08 09:42:47.770250+0800 09-線程[1815:57106] test - <NSThread: 0x604000278ac0>{number = 17, name = (null)}
2018-11-08 09:42:47.770243+0800 09-線程[1815:57105] test - <NSThread: 0x6040002797c0>{number = 16, name = (null)}
2018-11-08 09:42:49.775898+0800 09-線程[1815:57107] test - <NSThread: 0x604000279b40>{number = 18, name = (null)}
2018-11-08 09:42:49.775904+0800 09-線程[1815:57108] test - <NSThread: 0x604000277f80>{number = 19, name = (null)}
2018-11-08 09:42:49.775948+0800 09-線程[1815:57109] test - <NSThread: 0x604000279980>{number = 20, name = (null)}
2018-11-08 09:42:49.776003+0800 09-線程[1815:57111] test - <NSThread: 0x604000278080>{number = 22, name = (null)}
2018-11-08 09:42:49.776007+0800 09-線程[1815:57110] test - <NSThread: 0x604000279a00>{number = 21, name = (null)}

每次相差2秒執(zhí)行5個(gè)線程的操作薄嫡,如果要做成同步鎖的話氧急,傳入的信號(hào)量的值為1就好了。
@synchroized

- (void)synchronizedTestTest
{
    @synchronized([self class]) {
        sleep(1);
        NSLog(@"123 - %@",[NSThread currentThread]);
    }
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    for (int i = 0; i < 20; i++) {
        [[[NSThread alloc] initWithTarget:self selector:@selector(synchronizedTestTest) object:nil] start];
    }
}

打印結(jié)果

2018-11-08 09:52:08.104731+0800 09-線程[1990:66615] 123 - <NSThread: 0x60400027e780>{number = 3, name = (null)}
2018-11-08 09:52:09.107712+0800 09-線程[1990:66616] 123 - <NSThread: 0x60400027e140>{number = 4, name = (null)}
2018-11-08 09:52:10.112815+0800 09-線程[1990:66617] 123 - <NSThread: 0x60400027eb00>{number = 5, name = (null)}
2018-11-08 09:52:11.118213+0800 09-線程[1990:66618] 123 - <NSThread: 0x60400027e1c0>{number = 6, name = (null)}
2018-11-08 09:52:12.123081+0800 09-線程[1990:66619] 123 - <NSThread: 0x60400027ea80>{number = 7, name = (null)}
2018-11-08 09:52:13.124789+0800 09-線程[1990:66620] 123 - <NSThread: 0x60400027e840>{number = 8, name = (null)}
2018-11-08 09:52:14.130562+0800 09-線程[1990:66621] 123 - <NSThread: 0x60400027ea40>{number = 9, name = (null)}
2018-11-08 09:52:15.133153+0800 09-線程[1990:66622] 123 - <NSThread: 0x60400027e180>{number = 10, name = (null)}

@synchronized 鎖的對象可以是任何對象岂座,只要在需要的場景使用相同的一個(gè)對象作為鎖就可以了

NSConditionLock


- (void)viewDidLoad {
    [super viewDidLoad];
 self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [[[NSThread alloc] initWithTarget:self selector:@selector(__one) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__two) object:nil] start];
    
    [[[NSThread alloc] initWithTarget:self selector:@selector(__three) object:nil] start];
}

- (void)__one
{
    [self.conditionLock lock];
    
    NSLog(@"__one");
    sleep(1);
    
    [self.conditionLock unlockWithCondition:2];
}

- (void)__two
{
    [self.conditionLock lockWhenCondition:2];
    
    NSLog(@"__two");
    sleep(1);
    
    [self.conditionLock unlockWithCondition:3];
}

- (void)__three
{
    [self.conditionLock lockWhenCondition:3];
    
    NSLog(@"__three");
    
    [self.conditionLock unlock];
}

執(zhí)行結(jié)果:

2018-11-08 09:58:50.013405+0800 09-線程[2114:72695] __one
2018-11-08 09:58:51.017919+0800 09-線程[2114:72696] __two
2018-11-08 09:58:52.023380+0800 09-線程[2114:72697] __three

會(huì)依次執(zhí)行one态蒂、twothree费什,Condition的默認(rèn)條件是0

Atomic

atomic (原子性)钾恢,在屬性賦值的時(shí)候系統(tǒng)內(nèi)部會(huì)封裝一層spinlock進(jìn)行加鎖解鎖操作
nonatomic (非原子性),直接賦值

dispatch_barrier_sync

線程安全中鸳址,其實(shí)只要保證單寫多讀就可以瘩蚪,用dispatch_barrier_sync就可以實(shí)現(xiàn),在dispatch_barrier_sync執(zhí)行寫的操作稿黍,如圖


注: 此函數(shù)需要在創(chuàng)建的并行隊(duì)列執(zhí)行

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疹瘦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子巡球,更是在濱河造成了極大的恐慌言沐,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酣栈,死亡現(xiàn)場離奇詭異险胰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矿筝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門起便,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窖维,你說我怎么就攤上這事榆综。” “怎么了铸史?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵鼻疮,是天一觀的道長。 經(jīng)常有香客問我琳轿,道長陋守,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任利赋,我火速辦了婚禮,結(jié)果婚禮上猩系,老公的妹妹穿的比我還像新娘媚送。我一直安慰自己,他們只是感情好寇甸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布塘偎。 她就那樣靜靜地躺著疗涉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吟秩。 梳的紋絲不亂的頭發(fā)上咱扣,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機(jī)與錄音涵防,去河邊找鬼闹伪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛壮池,可吹牛的內(nèi)容都是我干的偏瓤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼椰憋,長吁一口氣:“原來是場噩夢啊……” “哼厅克!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橙依,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤证舟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后窗骑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體女责,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年慧域,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鲤竹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昔榴,死狀恐怖辛藻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情互订,我是刑警寧澤吱肌,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站仰禽,受9級特大地震影響氮墨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吐葵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一规揪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧温峭,春花似錦猛铅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堕伪。三九已至,卻和暖如春栗菜,著一層夾襖步出監(jiān)牢的瞬間欠雌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工疙筹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留富俄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓腌歉,卻偏偏與公主長得像蛙酪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子翘盖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容