多線程概念和NSThread

iOS多線程的學(xué)習(xí)總結(jié)

一個程序可有多個進(jìn)程案腺,一個進(jìn)程,可有多個線程康吵。且至少有一個線程劈榨。線程內(nèi)部是串行,但是每條線程也可以(并行)同時執(zhí)行不同任務(wù)晦嵌。
進(jìn)程相當(dāng)于工廠車間(內(nèi)存劃分空間)同辣,然后線程相當(dāng)于在里面干活的人拷姿,多線程,就是在這空間多個干活的人旱函!

關(guān)于多線程的好處

  • 適當(dāng)提高程序的效率
  • 適當(dāng)提高資源利用旅(cpu响巢,內(nèi)存利用率)

壞處

  • 創(chuàng)建線程“舴粒空間上沒的消耗:椬俟牛空間512kb ,主線程1mb券腔,事件消耗90 毫秒伏穆。一般開3~5條線程
  • 開啟大量線程會降低性能
  • cpu消耗加大
  • 程序更加復(fù)雜

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

1.pthread 跨平臺,可移植颅眶。幾乎不用
2.NSThread : 面向?qū)ο篁诔觯唵我子茫芍苯硬僮骶€程對象涛酗,但是生命周期需要程序員管理
3.GCD : 代替NSThread 多線程技術(shù)铡原,充分利用設(shè)備的多核(雙核,四核)商叹,生命周期不需要程序員管理燕刻,系統(tǒng)自動管理
4.NSOperation :基于gcd(底層是gcd),比gcd多了一些簡單實(shí)用功能剖笙,使用面向?qū)ο?卵洗,生命周期,自動管理弥咪,不需要程序員管理

如何獲得主線程

    [NSThread mainThread];

NSTread 的基本使用

創(chuàng)建方式一:

//創(chuàng)建線程的方式1
-(void)creatNewThread1
{
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"創(chuàng)建方法1"];
//線程對象的一些屬性
    thread.name = @"線程A";
    thread.threadPriority = 0.9 ; //優(yōu)先級 0.0 ~ 1.0
    [thread start]; //手動啟動線程
}
-(void)run:(NSString *)parm
{    NSLog(@"parm = %@" ,parm) ; 
        //當(dāng)前線程
    [NSThread currentThread];
 [NSThread isMainThread]; //是否是主線程
    [NSThread mainThread];//獲取主線程
}

創(chuàng)建方式二:

//創(chuàng)建線程的方式2过蹂,,分離子線程
-(void)creatNewThread2{
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"分離子線程"];
}

創(chuàng)建方式三:

//創(chuàng)建線程的方式3,,這種方式不需要手動開啟線程
-(void)creatNewThread2{
    [self performSelectorInBackground:@selector(run:) withObject:@"開啟后臺線程"];
}

創(chuàng)建方式四:繼承NSTread子類聚至。重寫main 酷勺,把任務(wù)封裝到main中

//從些 NSThread 子類,重寫main 方法扳躬,把任務(wù)封裝到main方法中

#import <Foundation/Foundation.h>
@interface XCThread : NSThread
@end
#import "XCThread.h"
@implementation XCThread
-(void)main
{
    [super main];
    NSLog(@"666");
}
@end

-(void)threadCreat4
{
    XCThread *tread = [[XCThread alloc] init];
    [tread start];
}
/* 打印
2017-11-15 22:52:48.615 NSTread基本使用[1003:32546] 666
2017-11-15 22:52:48.615 NSTread基本使用[1003:32546] 666
*/

如果想要創(chuàng)建多個線程只需要脆诉,把創(chuàng)建線程的代碼多執(zhí)行幾次就可以了 ,那么 1 相對于2贷币,3 方法好處呢击胜,那就是可以拿到線程對象,操作線程役纹。反正亦然偶摔。NStread的線程的生命周期,當(dāng)線程中的人物執(zhí)行完畢促脉,被釋放辰斋。

新建 就緒 運(yùn)行 阻塞 死亡 五中狀態(tài)
-(void)start , 線程進(jìn)入就緒狀態(tài) -> cpu來調(diào)度就會進(jìn)入運(yùn)行狀態(tài)信不,人物完畢,自動進(jìn)入死亡

//阻塞暫停線程 亡呵,設(shè)置睡眠時間
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//例子,讓線程睡
   [NSThread sleepForTimeInterval:2.0];

//強(qiáng)制停止線程
+(void)exit;
//死亡狀態(tài)硫戈,一旦線程死亡了锰什。就不能再次開啟這個線程
注意線程安全,經(jīng)典的賣票例子
//解決辦法加互斥鎖
//多個線程調(diào)用這個丁逝,賣票方法汁胆,即多個窗口賣票一樣
//賣票方法
-(void)saleTickt
{
    while (1) {
        //互斥鎖 :鎖必須是全局唯一的。比如self 就可以霜幼,其他全局的也可以@synchronized (必須全局才行)
        //1,注意加鎖的位置
        //2嫩码,注意加鎖的前提條件
        //3,加鎖代價罪既,耗費(fèi)性能
        //4铸题,加鎖結(jié)果,線程同步琢感。一開始多個線程是異步的
        @synchronized (self) {
            //鎖里面的方法
            if (_count > 0) {
                _count = _count - 1;
                NSLog(@"賣出去一張票");
            }else{
                NSLog(@"騷年沒有票了");
            }
        }
    }
}

互斥鎖

@synchronized (必須全局才行)
{
需要鎖定的代碼
}
*優(yōu)點(diǎn):能有效防止多線程搶同一塊資源丢间,造成同步存取數(shù)據(jù)的不安全。
*缺點(diǎn):需要耗費(fèi)大量的cpu資源
線程同步:多條線程同一條線上執(zhí)行驹针,實(shí)現(xiàn)方法加互斥鎖烘挫。默認(rèn)情況下,多條線程是異步執(zhí)行的柬甥。

原子和非原子屬性的選擇

nonatomic :非線程安全饮六,不會set 方法加鎖
atomic 非原子屬性,線程安全苛蒲,會給set 加鎖需要耗費(fèi)較大資源加鎖

線程間的通信

  • 一個線程傳遞數(shù)據(jù)給另一個線程
  • 一個線程執(zhí)行任務(wù)完成后卤橄,轉(zhuǎn)到另一個線程繼續(xù)執(zhí)行任務(wù)
    線程間的通信常用方法
//回到主線程
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

// onThread : 線程對象可回主線程可回子線程
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait

比如子線程下載圖片,下載完成圖片后回到主線程中進(jìn)行加載顯示的操作

//子線程下載圖片
-(void)downLoadImage
{
    NSString *str =  @"http://static.firefoxchina.cn/img/201710/4_59e999c8e6aa50.jpg";
    NSURL *url = [NSURL URLWithString:str];
    CFTimeInterval currentTime = CFAbsoluteTimeGetCurrent() ;
    //下載網(wǎng)絡(luò)圖片
    NSData *iamgeData = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:iamgeData];
    //回到主線程方法 ********方法1***********
    /*
     1,第一個參數(shù):回到主線程需要調(diào)用那個方法
     2.第二個參數(shù):前面方法需要傳遞的參數(shù)    
     3.第三個參數(shù):是否等待 ,撤防。如果為yes虽风,執(zhí)行到了 回到主線程performSelectorOnMainThread,
會立馬打印 x-x-x 寄月,如果為NO辜膝,那么會等showImage:方法執(zhí)行完畢才會打印x-x-x
     */
//方式1:回到主線程調(diào)用刷新,和方式2 取其一
 // [self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];

//方式2漾肮,回到主線程刷新厂抖,這種方式更靈活,也可以和子線程通信
    [self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];


    NSLog(@"x-x-x");
}
//主線程顯示圖片
-(void)showImage:(UIImage *)image
{
    //顯示imageview
    self.imageview.image = image ;
}

常駐子線程

需求克懊。一開始我們創(chuàng)建一個子線程 tread 忱辅。調(diào)用方法test 打印七蜘。結(jié)果是開啟了子線程并且打印了。因?yàn)樽泳€程任務(wù)執(zhí)行完畢墙懂。立馬就銷毀了 橡卤,雖然tread 是被strong強(qiáng)指針修飾,但是已經(jīng)沒有用死掉了损搬。所以我們點(diǎn)擊屏幕調(diào)用test1 方法碧库。在 tread線程里面調(diào)用。會報錯巧勤。嵌灰。下面是錯誤的寫法

@interface ViewController ()
@property (nonatomic,strong)NSThread * tread;
@end
@implementation ViewController

-(void)viewDidLoad
{
    [super viewDidLoad];
    //1,創(chuàng)建線程
    self.tread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];   
    [self.tread start];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 線程通信。也在 子線程  tread  線程調(diào)用test1 颅悉。
//因?yàn)樽泳€程在執(zhí)行 test 的時候沽瞭,任務(wù)完成立馬就銷毀了坛梁。所以會crash .那么怎么解決呢披坏。常駐子線程可以解決
    [self performSelector:@selector(test1) onThread:self.tread withObject:nil waitUntilDone:YES];
}
-(void)test
{
    NSLog(@"%s  %@ ",__func__ ,[NSThread currentThread]);
}

-(void)test1
{
    NSLog(@"%s  %@ ",__func__ ,[NSThread currentThread]);
}

那么我們該如何保持子線程不銷毀呢民珍?所以我們需要常駐子線程 ?? 玛瘸,應(yīng)用場景如網(wǎng)絡(luò)請求等公般。


@interface ViewController ()

@property (nonatomic,strong)NSThread * tread;

@end

@implementation ViewController

-(void)viewDidLoad
{
    [super viewDidLoad];
    //1,創(chuàng)建線程
    self.tread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];
    
    [self.tread start];
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 線程通信
    [self performSelector:@selector(test1) onThread:self.tread withObject:nil waitUntilDone:YES];
}

-(void)test
{
    NSLog(@"%s  %@ ",__func__ ,[NSThread currentThread]);
    //為了解決該任務(wù)執(zhí)行完畢棉浸。子線程就立馬銷毀問題锋喜,我們開啟runloop
    //1 , 獲取子線程對應(yīng)的runloop
    NSRunLoop *runloop = [NSRunLoop currentRunLoop];
    
    //2 , 因?yàn)閞unloop必須要有一個timer 活著 source 保證運(yùn)行狀態(tài) 精居,所以我們可以添加一個timer 活著 source 事件
     //方式 一:添加一個timer
//    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0f target:self selector:@selector(run) userInfo:nil repeats:YES];
//    [runloop addTimer:timer forMode:NSDefaultRunLoopMode];
   
    //方式 二 : 添加一個source 搂鲫。端口事件
    [runloop  addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    
    //可選傍药。  10s 后退出runloop 。 配合方式 二 的
    [runloop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    
    NSLog(@"end");
    
}

-(void)test1
{
    NSLog(@"%s  %@ ",__func__ ,[NSThread currentThread]);
}
/* 打印結(jié)果魂仍,一個子線程拐辽。執(zhí)行了 test   又執(zhí)行了 test1
  2017-11-14 00:23:37.152 RunloopDemo[1732:112273] -[ViewController test]  <NSThread: 0x6000000766c0>{number = 3, name = (null)} 
2017-11-14 00:23:38.929 RunloopDemo[1732:112273] -[ViewController test1]  <NSThread: 0x6000000766c0>{number = 3, name = (null)} 
2017-11-14 00:23:39.683 RunloopDemo[1732:112273] -[ViewController test1]  <NSThread: 0x6000000766c0>{number = 3, name = (null)} 

*/

如有不妥:請大神輕噴??
NSOperation簡單的入門
GCD入門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市擦酌,隨后出現(xiàn)的幾起案子俱诸,更是在濱河造成了極大的恐慌,老刑警劉巖赊舶,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睁搭,死亡現(xiàn)場離奇詭異,居然都是意外死亡笼平,警方通過查閱死者的電腦和手機(jī)园骆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寓调,“玉大人锌唾,你說我怎么就攤上這事。” “怎么了晌涕?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵滋捶,是天一觀的道長。 經(jīng)常有香客問我余黎,道長重窟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任惧财,我火速辦了婚禮亲族,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘可缚。我一直安慰自己,他們只是感情好斋枢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布帘靡。 她就那樣靜靜地躺著,像睡著了一般瓤帚。 火紅的嫁衣襯著肌膚如雪描姚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天戈次,我揣著相機(jī)與錄音轩勘,去河邊找鬼。 笑死怯邪,一個胖子當(dāng)著我的面吹牛绊寻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播悬秉,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼澄步,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了和泌?” 一聲冷哼從身側(cè)響起村缸,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎武氓,沒想到半個月后梯皿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡县恕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年东羹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弱睦。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡百姓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出况木,到底是詐尸還是另有隱情垒拢,我是刑警寧澤旬迹,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站求类,受9級特大地震影響奔垦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尸疆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一椿猎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寿弱,春花似錦犯眠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至噪矛,卻和暖如春量蕊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艇挨。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工残炮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缩滨。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓势就,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脉漏。 傳聞我的和親對象是個殘疾皇子蛋勺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

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

  • .一.進(jìn)程 進(jìn)程:是指在系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序,每個進(jìn)程之間是獨(dú)立的,每個進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空...
    IIronMan閱讀 4,486評論 1 33
  • 多線程 在iOS開發(fā)中為提高程序的運(yùn)行效率會將比較耗時的操作放在子線程中執(zhí)行鸠删,iOS系統(tǒng)進(jìn)程默認(rèn)啟動一個主線程抱完,用...
    郭豪豪閱讀 2,597評論 0 4
  • 目錄 一、基本概念1.多線程2.串行和并行刃泡, 并發(fā)3.隊(duì)列與任務(wù)4.同步與異步5.線程狀態(tài)6.多線程方案 二巧娱、GC...
    BohrIsLay閱讀 1,581評論 5 12
  • Object C中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼烘贴,方法是什么禁添?如果想延時執(zhí)行代碼、方法又是什么桨踪? 1...
    AlanGe閱讀 1,739評論 0 17
  • 本文選譯自《Threading Programming Guide》老翘。 導(dǎo)語 線程技術(shù)作為在單個應(yīng)用程序中并發(fā)執(zhí)行...
    巧巧的二表哥閱讀 2,437評論 4 24