多線程

什么是多線程

多線程:顧名思義就是多條線程同時存在,在實(shí)際開發(fā)中是非常重要的。
要了解多線程,我們首先要了解的是進(jìn)程。

什么是進(jìn)程

簡單說進(jìn)程就是我們運(yùn)行中的程序,運(yùn)行中的程序?qū)?yīng)相應(yīng)的進(jìn)程,每個程序都有一個進(jìn)程來對應(yīng),那么程序(進(jìn)程)是怎么執(zhí)行的呢。那就要談到線程了。

什么是線程,與進(jìn)程有什么關(guān)系呢

進(jìn)程是執(zhí)行程序是靠線程來執(zhí)行的,進(jìn)程與線程的關(guān)系就類似工長的車間與流水線,
每個進(jìn)程的都要靠一個或多個流水線來完成。那么為什么要使用多線程呢

多線程優(yōu)點(diǎn)缺點(diǎn)

優(yōu)點(diǎn)

  • 適當(dāng)?shù)奶岣叱绦虻膱?zhí)行效率(多個線程同時執(zhí)行)
  • 適當(dāng)?shù)奶岣吡速Y源利用率(cpu,內(nèi)存)

多線程缺點(diǎn)

  • 占用一定的內(nèi)存空間
  • 線程越多cpu的調(diào)度開銷越大
  • 程序的復(fù)雜度會上升(會涉及到多線程的通信,多線程共用一個資源)

既然有多線程這個東西,我們就像這東西究竟在實(shí)際應(yīng)用中是什么樣的呢!

ios中實(shí)際應(yīng)用

主線程

我們了解應(yīng)用首先要知道線程有哪些種類

主線程
  • 程序一啟動就會創(chuàng)建的線程(主線程,UI線程)
  • 主要是更新UI
  • 處理UI事件

主線程注意事項

  • 費(fèi)時操作要放在子線程中否則會阻塞線程

子線程

處理耗時操作

插-多線程原理

多線程時間上是cpu在多條線程上快速切換執(zhí)行,造成了給我們感覺上是同時執(zhí)行

通過上面的介紹我們知道了子線程的重要性,但是我們怎么創(chuàng)建子線程呢?有多少中方法呢?

多線程.jpeg

上圖介紹了現(xiàn)今各種多線程技術(shù),通過上面這些類我們就能夠創(chuàng)建線程

Pthread

現(xiàn)在使用較少,可以看出它使用的是c語言,一般我們使用的方法是[Pthread currentThread];
創(chuàng)建方法

- (IBAction)testButton:(UIButton *)sender {

//初始化一個線程
 pthread_t thread;
//下方法是在線程中執(zhí)行相應(yīng)的函數(shù)
    //第一個參數(shù)傳遞的時地址,傳遞地址才能在函數(shù)中更改這個對象
    //第三個是指向函數(shù)的指針
    pthread_create(&thread, NULL, run, NULL);
}
//創(chuàng)建一個函數(shù)
void * run(void *param)
{
  //耗時操作
    for (int i = 1; i++; i>1) {
    NSLog(@"i= %@",[NSThread currentThread]);
    }

    return NULL;
}

那么我們就可以將函數(shù)操作放在函數(shù)中,那么這個函數(shù)就會在子線程中執(zhí)行了

NSthread

一共有三種創(chuàng)建線程的方式

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self createThread1];
}
- (void)createThread3
{
    [self performSelectorInBackground:@selector(run:) withObject:@"rose"];
}
- (void)createThread2
{
    //創(chuàng)建線程并開啟
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"jack"];
}
- (void)createThread1
{
    //通過Nsthread創(chuàng)建一個對象
    CJNSthread *thread = [[CJNSthread alloc]initWithTarget:self selector:@selector(run:) object:@"jack"];
    //開啟線程,(就會執(zhí)行線程中的方法)
    [thread start];
    
    //常用方法
    thread.name = @"haha";
}
- (void)run:(NSString *)parm
{
    for (NSInteger i = 0; i < 100; i++) {
        NSLog(@"%@",[NSThread currentThread ]);
    }
}

以上三種方式都可以創(chuàng)建線程
三種方式對比
第二三中方式創(chuàng)建線程比較簡單,直接創(chuàng)建,自動執(zhí)行,但是相對第一種就不能拿到線程不能對線程進(jìn)行更詳細(xì)的操作。
三種線程銷毀時間,我們使用第一種方式創(chuàng)建線程并且自定義一個類繼承自NSThread,重寫delloc方法,可以看到在方法調(diào)用完畢自動被類銷毀,所以創(chuàng)建是我們要手動的,銷毀是自動的。

線程狀態(tài)

線程從開始到結(jié)束都有什么狀態(tài)呢

    CJNSthread *thread = [[CJNSthread alloc]initWithTarget:self selector:@selector(run:) object:@"jack"];

上面代碼創(chuàng)建線程-新建線程

    [thread start];

上面代碼開啟線程- 就緒狀態(tài)
cpu調(diào)度-運(yùn)行狀態(tài)
如果阻塞線程-阻塞狀態(tài)
線程執(zhí)行完畢-進(jìn)入死亡狀態(tài)

阻塞線程代碼

+ (void)sleepUnitlDate:(NSDate *)date;
+ (void)sleepTimeInterval:(NSTimeinterval)ti;

使用多線程的隱患

多條線程同時訪問相同資源進(jìn)行操作,很容易造成數(shù)據(jù)錯亂。
解決方案:互斥鎖-訪問數(shù)據(jù)的線程增加一把鎖,線程結(jié)束之后再解鎖,其他線程才能訪問這個資源


@interface ViewController ()
//創(chuàng)建三個售票員
@property (nonatomic , strong)NSThread *thread01;
@property (nonatomic , strong)NSThread *thread02;
@property (nonatomic , strong)NSThread *thread03;
@property (nonatomic , assign)NSInteger ticketCount;
//創(chuàng)建所對象,必須是相同的鎖對象才能夠鎖住
@property (nonatomic , strong)NSObject *obj;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.thread01 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
    self.thread01.name = @"售票員01";
    self.thread02 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
     self.thread02.name = @"售票員02";
    self.thread03 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
     self.thread03.name = @"售票員03";
    self.ticketCount = 100;
    self.obj = [[NSObject alloc]init];

    
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.thread01 start];
    [self.thread02 start];
    [self.thread03 start];
}
- (void)saleTicket
{
    
    while (1) {
       //增加線程鎖,在取出資源之前
         @synchronized(self.obj){
        NSInteger count = self.ticketCount;
        if (count > 0) {
            //為了看得更加明顯,我們將線程睡眠
            [NSThread sleepForTimeInterval:0.1];
            self.ticketCount = count - 1;
            NSLog(@"%@票已經(jīng)賣完,還剩%zd張",[NSThread currentThread].name,self.ticketCount);
        }else
        {
            NSLog(@"票已經(jīng)賣完了");
            break;
        }
    }

    }
}

互斥鎖(線程同步技術(shù))

缺點(diǎn):互斥所是很耗費(fèi)cpu資源的
使用:多個線程涉及數(shù)據(jù)的訪問
線程同步:多條線程在同一條線程上執(zhí)行。
相關(guān):atomic 和nonatomic 原子性和非原子性
使用atomic:定義屬性的時候,屬性的set方法就會加鎖,會非常耗盡性能(因為屬性使用頻繁)
建議:所以使用的時候我們一般都直接定義nonatomic,個別需要的時候我們再使用atomic

線程通信

我們在開啟子線程執(zhí)行耗時操作,那么如何我們需要執(zhí)行操作后立即就更新到界面上,我們就有了回到主線程更新界面的需求,所以我們要學(xué)會線程通信。

在子線程中操作
[self performSelectorInBackground: withObject:l];
回到住線程中操作
[self performSelectorOnMainThread:]
//waitUnitilDone是否等待線程執(zhí)行完畢后繼續(xù)執(zhí)行
[self.imageView performSelector: onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
最后編輯于
?著作權(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)容

  • 又來到了一個老生常談的問題,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個問題開始,來談?wù)劜?..
    tangsl閱讀 4,317評論 0 23
  • Object C中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼,方法是什么?如果想延時執(zhí)行代碼、方法又是什么? 1...
    AlanGe閱讀 1,914評論 0 17
  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來是分開三篇的,后來想想還是整...
    coder_pig閱讀 1,772評論 2 17
  • 進(jìn)程 1:進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序,進(jìn)程是程序在計算機(jī)上的一次執(zhí)行活動。 2:每個進(jìn)程之間是相互獨(dú)立...
    沒有夢想_何必遠(yuǎn)方閱讀 924評論 0 3
  • 線程概述 有些程序是一條直線,起點(diǎn)到終點(diǎn);有些程序是一個圓,不斷循環(huán),直到將它切斷一個運(yùn)行著的程序就是一個進(jìn)程或者...
    褪而未變閱讀 357評論 0 0

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