iOS平臺提供了非常優秀的多線程支持,程序可以通過非常簡單的方式來啟動多線程,iOS平臺不僅提供了NSThread類來創建多線程,還提供了GCD方式來簡化多線程編程,提供了NSOperation和NSOperationQueue支持多線程編程。總之,iOS已經盡力降低開發多線程應用的繁瑣,努力讓開發者能輕松、簡單地開發多線程應用.
幾乎所有的操作系統都支持同時運行多個任務,一個任務通常就是一個程序,每個運行中的程序就是一個進程.當一個程序運行時,內部可能包含了多個順序執行流,每個順序執行流就是一個線程.
任務->進程->線程
所有運行中的任務通常對應一個進程(PRocess),當一個程序進入內存運行后,即變成一個進程,進程是處于運行過程中的程序,并且具有一定的獨立功能,進程是系統進行資源分配和調度的一個獨立單位。
進程包含如下3個特征 | |
獨立性 | 進程是系統中獨立存在的實體,它可以擁有自己獨立的資源,每一個進程都擁有自己私有的地址空間。在沒有經過進程本身允許的情況下,一個用戶進程不可以直接訪問其他進程的地址空間。 |
動態性 | 進程與程序的區別在于,程序只是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合。在進程中加入了時間的概念,進程具有自己的生命周期和各種不同的狀態,這些概念在程序中都是不具備的。 |
并發性 | 多個進程可以在單個處理器上并發執行,多個線程之間不會互相影響。 |
注 意 | 并發性(concurrency)和并行性(parallel)是兩個概念, 并行指在同一時刻,有多條指令在多個處理器上同時執行; 并發指在在同一時刻只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。 |
線 程 | |
多線程使得同一個進程可以同時并發處理多個任務。線程(Thread)也被稱作輕量級進程(Lightweight Process),線程是進程的執行單元。線程在程序中是獨立的、并發的執行流。當進程被初始化后,主線程就被創建了。對于絕大多數的應用程序來說,通常僅要求有一個主線程,但是我們也可以在該進程內創建多條順序執行流,這些順序執行流就是線程,每條線程也是互相獨立的。 線程是進程的組成部分,一個進程可以擁有多個線程,一個線程必須有一個父進程。線程可以擁有自己的堆棧、自己的程序計數器和自己的局部變量,但不再擁有系統資源,它與父進程的其他線程共享該進程所擁有的全部資源。因為多個線程共享父進程里的全部資源,因此編程更加方便;但必須更加小心,我們必須確保線程不會妨礙同一進程里的其他線程 簡而言之:一個程序運行后至少有一個進程,一個進程里可以包含多個線程,但至少要包含一個線程.操作系統可以同時執行多個任務,每個任務就是進程;進程可以同時執行多個任務,每個任務就是線程. |
線程在程序中是獨立的、并發的執行流,與分隔的進程相比,進程中的線程之間的隔離程度要小。它們共享內存、文件句柄和其他每個進程應用的狀態。同一個進程中的線程都有共性----多個線程將共享同一個進程虛擬空間。線程共享的環境包括:進程代碼段、進程的公有數據等。利用這些共享的數據等,線程很容易實現相互之間的通信。
多線程的優點 | |
1 | 進程間不能共享內存,但線程之間共享內存非常容易。 |
2 | 系統創建進程需要為該進程重新分配系統資源,但創建線程則代價小得多,因此使用多線程來實現多任務并發比多進程的效率高。 |
3 | iOS提供了多種多線程實現方式,從而簡化了iOS的多線程編程。 |
iOS大致提供了如下3種多線程編程的技術 | |
1 | 使用NSThread實現多線程。 |
2 | 使用NSOperation與NSOperationQueue實現多線程 |
3 | 使用GCD(Grand Central Dispatch)實現多線程 |
iOS使用NSThread類代表線程,創建新線程也就是創建NSThread對象。
創建NSThread有兩種方式。
-(id)initWithTarget:(id)target selector:(SEL)selector object:(id)arg | 創建一個新線程對象 | |
+ (void)detachNewThreadSelector:(SEL)selector object:(id)target withObject:(id)arg | 創建并啟動新線程 | |
+ currentThread: | currentThread是NSThread類的類方法,該方法總是返回當前正在執行的線程對象 | |
setName: | 可以通過name方法返回指定線程的名字 | |
上面兩種方式的本質都是將target對象的selector方法轉換為線程執行體,其中selector方法最多可以接收一個參數,而arg就代表傳給selector方法的參數. | ||
提 示 | target對象的selector方法的方法體代表了線程需要完成的任務,因此相當于把target對象的selector方法轉換為線程執行體. | |
區 別 | 第1種方式是一個實例方法,該方法返回一個NSThread對象,必須調用start方法啟動線程 第2種方式不會返回NSThread對象,因此這種方式直接創建并啟動線程. | |
啟動線程使用start方法,線程啟動之后并不是立即進入運行狀態,線程被啟動后處于就緒狀態,當系統調整線程后,線程才會進入運行狀態.
如果程序希望調用子線程的start方法后子線程立即開始執行,程序可以使用[NSThread sleepForTimeInterval:0.001];
讓當前運行的線程(主線程)睡眠1毫秒---1毫秒就夠了,因為在這1毫秒內CPU不會空閑,它會去執行另一個處于就緒狀態的線程,這樣就可以讓子線程立即獲得執行.
線程會以以下3種方式之一結束,結束后就處于死亡狀態. | |
線程執行體方法執行完成,線程正常結束. | |
線程執行過程中出現錯誤 | |
直接調用NSThread類的exit方法來中止當前正在執行的線程. | |
注意 | 當主線程結束時,其他線程不受任何影響,并不會隨之結束.一旦子線程啟動起來后,它就擁有和主線程相同的地位,它不會受主線程的影響. |
為了測試某個線程是否正在運行,可以調用線程對象的isExcuting、isFinished方法,當線程正處于執行過程中時,調用isExecuting方法就會返回YES;當線程執行完成后,調用isFinished方法就會返回YES。
上面程序中①號代碼調用了thread對象的cancel方法,該方法用于向thread對象發送取消信號,這樣即可使得thread對象的isCancelled方法
返回YES------接下來程序在線程執行體方法中線判斷thread對象d的isCancelled是否為YES,如果該對象的isCancelled為YES,程序就調用Thread類的exit方法終止當前正在執行的循環,這樣就可以從UI線程終止子線程了.
需要讓當前正在執行的線程暫停一段時間,并進入阻塞狀態,則可以通過調用NSThread類的靜態。sleepXxx方法來完成。
NSThread類提供了如下兩個控制線程暫停的類方法 | |
+(void)sleepUntilDate:(NSDate *)aDate: | 讓當前正在執行的線程暫停到aDate代表的時間,并進入阻塞狀態 |
+(void)sleepForTimeInterval:(NSTimeInterval)ti: | 讓當前正在執行的線程暫停ti秒,并進入阻塞狀態. |
當當前線程調用sleepXxx方法進入阻塞狀態后,在其睡眠時間段內,該線程不會獲得執行的機會,即使系統中沒有其他科執行的線程,處于阻塞狀態的線程也不會執行,因此sleepXxx方法常用來暫停線程的執行.
[NSThread sleepForTimeInterval:0.5];
用于控制當前正在執行的線程暫停0.5秒
每個線程執行時都具有一定的優先級,優先級高的線程獲得較多的執行機會,而優先級低的線程則獲得較少的執行機會.每個子線程默認的優先級為0.5.
NSThread提供了如下實例方法和類方法來設置獲取線程的優先級
+ threadPriority: | 該類方法獲取當前正在來設置執行的線程的優先級 | |
- threadPriority: | 該實例方法獲取調用該方法的線程對象的優先級 | |
+ setThreadPriority:(double)priority: | 該類方法用于設置當前正在執行的線程的優先級 | |
- setThreadPriority:(double)priority: | 該實例方法用于設置該方法的線程對象的優先級 | |
在上面方法中,setThreadPriority:(double)priority方法的參數可以是一個double類型的浮點數,范圍為0.0~1.0,其中1.0代表最高優先級,0.0代表最低優先級. | ||
下面代碼中使用了setThreadPriority:方法來改變主線程的優先級,并使用該方法改變了兩個線程的優先級,從而可以看到高優先級的線程將會獲得更多的執行機會. | ||
代 碼 片段 | 1 @implementation LCViewController 2 3 - (void)viewDidLoad 4 5 { 6 7 [super viewDidLoad]; 8 9 NSLog(@”線程A的優先級為:%g”,[NSThread threadPriority]);10 11 // 創建第1個線程對象12 13 NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector@selector(run) object:nil];14 15 // 設置第1個線程對象的名字16 17 thread1.name = @”線程A”;18 19 NSLog(@”線程A的優先級為: %g”, thread1.threadPriority);20 21 // 設置使用最低優先級22 23 thread1.threadPriority = 0.0;24 25 // 創建第2個線程對象26 27 NSThread* thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];28 29 // 設置第2個線程對象的名字30 31 thread2.name = @”線程B”;32 33 NSLog(@”線程B的優先級為:%g”, thread2.threadPriority);34 35 // 設置使用最高優先級36 37 thread2.threadPriority = 1.0;38 39 // 啟動兩個線程40 41 [thread1 start];42 43 [thread2 start];44 45 }46 47 - (void)run48 49 {50 51 for(int i= 0; i < 100; i++)52 53 {54 55 NSLog(@”----%@-----%d”,[NSThread currentThread].name, i);56 57 }58 59 }60 61 @end
// 上面程序在改變線程A、線程B的優先級之前,先輸出線程A、線程B的優先級,在默認情況下,新建線程的優先級都是0.5.程序中改變了線程A的優先級為0.0,這樣線程A將會獲得較少的執行機會:接下來程序將線程B的優先級設為1.0,這樣線程B將會獲得更多的執行機會. | |
新聞熱點
疑難解答