iOS学习笔记11-多线程入门
生活随笔
收集整理的這篇文章主要介紹了
iOS学习笔记11-多线程入门
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、iOS多線程
iOS多線程開發有三種方式:
iOS在每個進程啟動后都會創建一個主線程,更新UI要在主線程上,所以也稱為UI線程,是其他線程的父線程。
線程和進程的區別傻傻分不清楚:
- 線程(thread):用于指代獨立執行的代碼段。
- 進程(process):用于指代一個正在運行的可執行程序,它可以包含多個線程。
二、NSThread
NSThreadhi輕量級的多線程開發,需要自己管理線程生命周期
創建線程主要實現方法:
/* 直接將操作添加到新線程中并執行,該方法無法拿到線程對象 */ + (void)detachNewThreadSelector:(SEL)selector?/* 方法名 */toTarget:(id)target?/* 調用對象 */ withObject:(id)argument; /* 參數 */ /* 創建線程對象,初始化線程任務,調用start方法啟動線程 */ - (instancetype)initWithTarget:(id)target?/* 調用對象 */ selector:(SEL)selector?/* 方法名 */ object:(id)argument;/* 參數 */實際使用:
/* 創建一個線程,初始化任務,創建線程并不會啟動線程 */ NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadImage) object:nil]; [thread start];//啟動線程 /* 直接將操作添加到新線程并啟動線程 */ [NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];- 每個線程的實際執行順序并不一定按啟動順序執行
- 如果是單核CPU,多線程是并發,分時間片切換執行不同線程,多核CPU的多線程才是真正的并行運算。
線程狀態分為:
- isExecuting(正在執行)
- isFinished(已經完成)
- isCancellled(已經取消)
下面是常用方法來控制線程:
/* 讓線程休眠 */ + (void)sleepUntilDate:(NSDate *)date;/* 讓當前執行線程休眠到某個時間 */ + (void)sleepForTimeInterval:(NSTimeInterval)time;/* 讓當前執行線程休眠固定多少秒 */ /* 終止線程 */ + (void)exit; /* 停止線程,注意在主線程中調用僅僅只是設置線程狀態,不會立刻停止線程 */ - (void)cancel;實例:
NSThread *thread = threads[i]; //判斷線程是否完成,如果沒有完成則設置為取消狀態 //注意設置為取消狀態僅僅是改變了線程狀態而言,并不能立刻終止線程 if ( !thread.isFinished ) { [thread cancel]; } //線程休眠2秒 [NSThread sleepForTimeInterval:2.0];我們知道了控制單個線程,怎么在線程之間進行通信呢?
下面是線程間通信的常用方法:
/* 在后臺執行一個操作,本質就是重新創建一個線程執行當前方法 */ - (void)performSelectorInBackground:(SEL)aSelectorwithObject:(id)arg; /* 在指定的線程上執行一個方法,需要用戶創建一個線程對象 */ - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait; /* 在主線程上執行一個方法 */ - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;三、NSOperation
只要將NSOperation放入NSOperationQueue線程隊列中,就會啟動執行。
NSOperationQueue負責管理、執行所有的NSOperation,這樣更加容易管理線程總數和控制線程之間的依賴。
NSOperation是個基類,我們直接使用的是它的子類:
- NSInvocationOperation:調用方法SEL的方式執行線程可以使用它
- NSBlockOperation:調用Block的方式執行線程可以使用它
下面是使用實例:
//創建Invocation線程 NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImage) object:nil]; //注意如果直接調用start方法,則此操作會在主線程中調用 // [invocationOperation start];//一般不會這么操作,而是添加到NSOperationQueue中 //創建線程隊列 NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; operationQueue.maxConcurrentOperationCount = 5;//設置最大并發線程數 //注意添加到線程隊列后,隊列里的線程就會開始執行 [operationQueue addOperation:invocationOperation]; //創建Block線程 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ [self loadImage:[NSNumber numberWithInt:0]]; }]; //添加進線程隊列 [operationQueue addOperation:blockOperation];如果覺得添加NSBlockOperation線程麻煩,還有個簡單的方法,是NSOperationQueue的對象方法:
// 快捷添加NSBlockOperation [operationQueue addOperationWithBlock:^{[self loadImage:[NSNumber numberWithInt:0]]; }];我說過NSOperationQueue可以控制線程之間的依賴,這是怎么一回事呢?想象一種場景,加載多個圖片,但我想最后一張圖片一定要先加載,其他圖片加載的前提就是最后一張圖片要加載完成,這時候就可以使用依賴了。非常簡單。
多圖片加載實例:
- (void)loadImageWithMultiThread{int count = ROW_COUNT*COLUMN_COUNT;//創建線程隊列NSOperationQueue *operationQueue = [[NSOperationQueue alloc]init]; operationQueue.maxConcurrentOperationCount = 5;//設置最大并發線程數 //創建加載最后一張圖片的線程 NSBlockOperation *lastBlockOperation = [NSBlockOperation blockOperationWithBlock:^{ [self loadImage:[NSNumber numberWithInt:(count-1)]]; }]; //創建多個線程用于下載其他圖片 for (int i=0; i<count-1; ++i) { //創建多線程操作 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ [self loadImage:[NSNumber numberWithInt:i]]; }]; //設置依賴操作為最后一張圖片加載操作,只有最后一張圖片加載完成,其他圖片才開始陸續加載 [blockOperation addDependency:lastBlockOperation]; [operationQueue addOperation:blockOperation]; } //將最后一個圖片的加載線程加入線程隊列 [operationQueue addOperation:lastBlockOperation]; }四、GCD
GCD中也有一個類似于NSOperationQueue的隊列,GCD統一管理整個隊列中的任務,GCD是C語言下的框架。
GCD中的隊列分為并行隊列和串行隊列:
- 串行隊列(serial):只有一個線程,加入到隊列中的操作按添加順序依次執行。
- 并發隊列(concurrent):有多個線程,操作進來之后它會將這些隊列安排在可用的處理器上,同時保證先進來的任務優先處理,但不是順序的。
其實在GCD中還有一個特殊隊列就是主隊列,用來執行主線程上的操作任務。
GCD執行方式也分為異步執行和同步執行:
- dispatch_async(異步執行) :不管隊列中的任務執行完還是沒執行完,直接將任務追加到隊列
- dispatch_sync(同步執行) : 等隊列中的任務執行完,再將任務追加到隊列
串行隊列和并發隊列的創建:
/*創建一個隊列第一個參數:隊列名稱第二個參數:隊列類型,DISPATCH_QUEUE_SERIAL串行,DISPATCH_QUEUE_CONCURRENT并發注意:GCD的queue不是指針類型 */ dispatch_queue_t serialQueue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL); dispatch_queue_t concurrentQueue = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT); /* 使用dispatch_get_global_queue()?方法取得一個全局的并發隊列 */ dispatch_queue_t?globalQueue?=?dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);隊列的異步執行和同步執行:
//異步執行隊列任務,第一個參數是隊列,第二個參數是任務Block dispatch_async(queue, ^{[self loadImage:[NSNumber numberWithInt:i]]; }); //同步執行隊列任務,第一個參數是隊列,第二個參數是任務Block dispatch_sync(queue, ^{ [self loadImage:[NSNumber numberWithInt:i]]; });- 在GDC中一個操作是多線程執行還是單線程執行,取決于當前隊列類型和執行方法,只有隊列類型為并行隊列并且使用異步方法執行時才能在多個線程中并發執行。
- 串行隊列可以按順序執行,并行隊列的異步方法無法確定執行順序。
- 更新UI界面最好采用同步方法,其他操作采用異步方法。
GCD的其他任務執行方法:
/* 重復執行某個任務,為了不阻塞線程可以使用dispatch_async()包裝一下再執行 */ dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));/* 單次執行一個任務,此方法中的任務只會執行一次,重復調用也沒辦法重復執行(單例模式中常用此方法)*/ dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); /* 常用:延遲delayInSeconds秒后在隊列queue執行block操作 */ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_queue_t queue, dispatch_block_t block);五、線程同步
為什么需要線程同步?因為要解決多線程的資源搶奪的問題
1.NSLock同步鎖
//初始化鎖對象 NSLock *myLock?=?[[NSLock alloc]?init]; //加鎖 [myLock?lock];//加鎖后,下面的代碼只能有一個線程進入執行 if (_imageNames.count?>?0) { name?=?[_imageNames lastObject]; [_imageNames removeObject:name]; } //使用完解鎖 [myLock?unlock];2.@synchronized代碼塊
//線程同步 @synchronized(self){if (_imageNames.count?>?0) { name?=?[_imageNames lastObject]; [_imageNames removeObject:name]; } }線程同步就不細講了,這是一個大塊知識。
轉載于:https://www.cnblogs.com/ming1025/p/6064523.html
總結
以上是生活随笔為你收集整理的iOS学习笔记11-多线程入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端框架选择
- 下一篇: cobbler 配置(转载)