多线程——NSThread、GCD、NSOperation
1、前言:
一個應(yīng)用程序就是一個進程,一個進程至少包含一個線程,程序啟動會自動創(chuàng)建一個主線程,負責(zé)UI界面的現(xiàn)實和控件事件的監(jiān)控。多線程可以更充分的利用系統(tǒng)CPU資源,一定程度上提升程序的性能。1個進程可以開啟多條線程,每條線程可以并行(同時)執(zhí)行不同的任務(wù)。在一個線程內(nèi)可以包含多個事物(要干的活),在線程內(nèi)依據(jù)先進先出的特性串行執(zhí)行……
2、NSThread
- (void)viewDidLoad {[super viewDidLoad];NSLog(@"main thread is %@",[NSThread mainThread]);//打印主線程(UI線程) }-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{//新開辟一條子線程,啟動子線程的時候調(diào)用downLoad方法,object是傳遞給子線程調(diào)用方法的參數(shù)NSThread *thread=[[NSThread alloc] initWithTarget:self selector:@selector(downLoad:) object:@"luseike"];//給子線程起一個名字thread.name=@"thread one";//開始子線程[thread start]; }-(void)downLoad:(NSString *)param{//打印當前線程(子線程)及其名字和傳遞過來的參數(shù)NSLog(@"begin downLoad--param is %@--current thread is %@ current name is %@",param,[NSThread currentThread],[NSThread currentThread].name); }?打印結(jié)果如下:
2014-06-26 23:03:05.724 NSThread[50292:60b] main thread is <NSThread: 0x8c421c0>{name = (null), num = 1}
2014-06-26 23:03:06.567 NSThread[50292:3807] begin downLoad--param is luseike--current thread is <NSThread: 0xa33c350>{name = thread one, num = 2} current name is thread one
可以看到主線程的num=1,子線程的num=2,證明確實是新開辟了一條線程來執(zhí)行downLoad操作。
還可以通過isMainThread判斷是否是主線程,setThreadPriority:(double)p來設(shè)置子線程的優(yōu)先級,優(yōu)先級的取值范圍在0.0~1.0之間,默認是0.5,值越大,優(yōu)先級越高,被執(zhí)行的幾率越大
還有兩種比較便捷的方式來創(chuàng)建子線程
1、[NSThread detachNewThreadSelector:@selector(downLoad:) toTarget:self withObject:@"luseike"];// 附加一個線程
2、[self performSelectorInBackground:@selector(downLoad:) withObject:@"haha"]; //在后臺執(zhí)行一個線程
這兩種方式創(chuàng)建的子線程都不需要調(diào)用start方法,系統(tǒng)會自動執(zhí)行對應(yīng)的方法,都也都沒有機會設(shè)置優(yōu)先級和咸線程名等更詳細的設(shè)置了,不過這個一般不重要
3、線程的狀態(tài)
線程從生到死大致有下面幾種狀態(tài):新建(new)、就緒(runnable)、運行(running)、阻塞(blocked)、死亡(dead)
一個線程被創(chuàng)建之后會放到一個叫做可調(diào)度線程池內(nèi),等待被CPU調(diào)度,當該線程獲得CPU的執(zhí)行權(quán)時,就進入到running狀態(tài)。running狀態(tài)的線程如果調(diào)用sleep方法或者在等待同步鎖,就會進入阻塞狀態(tài),進入阻塞狀態(tài)的線程會重新被放到可調(diào)度線程池內(nèi),等待被重新調(diào)度。線程任務(wù)執(zhí)行完畢,或者被強制退出,會進入dead狀態(tài),注意:進入dead狀態(tài)的線程并沒有被釋放內(nèi)存,只是不能用了而已,還存在內(nèi)存中。
?
4、控制線程的狀態(tài)
啟動線程:之前介紹過,調(diào)用start方法
阻塞(暫停)線程:
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
強制停止線程:+(void)exit;
多線程的安全隱患:當多個線程訪問同一塊資源時,很容易引發(fā)數(shù)據(jù)錯亂和數(shù)據(jù)安全問題。解決的機制就是使用鎖(互斥鎖),讓多條線程同步執(zhí)行,這就是傳說的線程同步技術(shù)。值得注意的是:鎖定一份代碼只用1把鎖,用多把鎖是沒有意義的;線程同步的前提是多條線程搶占同一塊資源
#import "ViewController.h"@interface ViewController () @property(nonatomic,strong)NSThread *thread1; @property(nonatomic,strong)NSThread *thread2; @property(nonatomic,strong)NSThread *thread3;@property(nonatomic,assign)int totalCount; @end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.totalCount=100;self.thread1=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];self.thread2=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];self.thread3=[[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; }-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{[self.thread1 start];[self.thread2 start];[self.thread3 start]; }-(void)saleTicket{int leftCount=self.totalCount;while (leftCount>0) {self.totalCount=leftCount--;NSLog(@"%@ sale one ticket,left %d",[NSThread currentThread],leftCount);}} @end
?如上代碼,模擬3個子線程同時訪問公共資源totalCount,每次操作減一,多線程訪問同一資源容易引起的數(shù)據(jù)安全問題已經(jīng)說明了,打印部分結(jié)果如下
2014-06-26 23:51:33.639 NSThread[63065:360b] <NSThread: 0xa06dd50>{name = (null), num = 3} sale one ticket,left 99
2014-06-26 23:51:33.639 NSThread[63065:3707] <NSThread: 0xa0706e0>{name = (null), num = 2} sale one ticket,left 99
2014-06-26 23:51:33.639 NSThread[63065:3f03] <NSThread: 0xa06ddf0>{name = (null), num = 4} sale one ticket,left 99
可以看到三個子線程都操作了totalCount變量,每次操作之后的值卻沒有變化……
互斥鎖的使用格式:
@synchronized(鎖對象) { // 需要鎖定的代碼? }
-(void)saleTicket{while (1) {@synchronized(self) { // 加鎖(只能用一把鎖)// 1.先檢查票數(shù)int count = self.totalCount;if (count > 0) {self.totalCount = count - 1;NSThread *current = [NSThread currentThread];NSLog(@"%@ sale one ticket, left %d tickets", current, self.totalCount);} else {[NSThread exit];}} } }?打印結(jié)果就可以正常顯示了……
5、GCD簡介
GCD是蘋果為了多核的并行運算提出的解決方案,會自動管理線程的生命周期,程序員只需要告訴GCD要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼。GCD中兩個核心概念:任務(wù)、隊列,將任務(wù)添加到隊列中,GCD會自動將隊列中的任務(wù)取出,放到對應(yīng)的線程中執(zhí)行,任務(wù)的取出遵循隊列FIFO原則:先進先出,后進后出。
GCD的隊列可以分為2大類型:并發(fā)隊列(可以讓多個任務(wù)并發(fā)執(zhí)行)、串行隊列
?
轉(zhuǎn)載于:https://www.cnblogs.com/luseike/p/3811128.html
總結(jié)
以上是生活随笔為你收集整理的多线程——NSThread、GCD、NSOperation的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Split字符串分割函数
- 下一篇: 如何配置Spring的XML文件及使用