国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

多線程

2019-11-14 18:17:22
字體:
來源:轉載
供稿:網友

一、iOS中多線程的實現方案

二、NSThread

1. 創建和啟動線程

一個NSThread對象就代表一條線程

創建、啟動線程

 1 - (void)viewDidLoad { 2     [super viewDidLoad]; 3     // 創建并開啟一條子線程 4     NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"參數"]; 5     // 線程一啟動,就會在線程thread中執行self的run方法 6     [thread start]; 7 } 8 /** 9  *  開啟子線程10  *11  *  @param param object傳進來的參數12  */13 - (void)run:(NSString *)param14 {15     NSLog(@"currentThread:%@--run--%@", [NSThread currentThread], param);16 }17 18 打印結果:19 <NSThread: 0x7fd5b2f207f0>{number = 2, name = (null)}--run--參數

主線程相關用法

1 + (NSThread *)mainThread; // 獲得主線程2 - (BOOL)isMainThread; // 是否為主線程3 + (BOOL)isMainThread; // 是否為主線程

其他用法

獲得當前線程NSThread *current = [NSThread currentThread];線程的調度優先級+ (double)threadPRiority;+ (BOOL)setThreadPriority:(double)p;- (double)threadPriority;- (BOOL)setThreadPriority:(double)p;調度優先級的取值范圍是0.0 ~ 1.0,默認0.5,值越大,優先級越高線程的名字- (void)setName:(NSString *)n;- (NSString *)name;

其他創建線程方式

創建線程后自動啟動線程[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];隱式創建并啟動線程[self performSelectorInBackground:@selector(run) withObject:nil];

上述2種創建線程方式的優缺點

  • 優點:簡單快捷
  • 缺點:無法對線程進行更詳細的設置

2. 控制線程狀態

啟動線程- (void)start; // 進入就緒狀態 -> 運行狀態。當線程任務執行完畢,自動進入死亡狀態阻塞(暫停)線程+ (void)sleepUntilDate:(NSDate *)date;+ (void)sleepForTimeInterval:(NSTimeInterval)ti;// 進入阻塞狀態強制停止線程+ (void)exit;// 進入死亡狀態

 注意:一旦線程停止(死亡)了,就不能再次開啟任務

3. 互斥鎖

互斥鎖使用格式:@synchronized(鎖對象) { // 需要鎖定的代碼  }

注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的

互斥鎖的優缺點

  • 優點:能有效防止因多線程搶奪資源造成的數據安全問題
  • 缺點:需要消耗大量的CPU資源 

互斥鎖的使用前提:多條線程搶奪同一塊資源

 

相關專業術語:線程同步

線程同步的意思是:多條線程按順序地執行任務

互斥鎖,就是使用了線程同步技術

4. 原子和非原子屬性

OC在定義屬性時有nonatomic和atomic兩種選擇

  • atomic:原子屬性,為setter方法加鎖(默認就是atomic)
  • nonatomic:非原子屬性,不會為setter方法加鎖

 atomic加鎖原理

1 @property (assign, atomic) int age;2 3 - (void)setAge:(int)age4 {5     @synchronized(self) {6         _age = age;7     }8 }

nonatomic和atomic對比

  • atomic:線程安全,需要消耗大量的資源
  • nonatomic:非線程安全,適合內存小的移動設備

5. 線程間通信

線程間通信的體現

1個線程傳遞數據給另1個線程

在1個線程中執行完特定任務后,轉到另1個線程繼續執行任務

線程間通信常用方法:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

三、GCD

1. 簡介

全稱是Grand Central Dispatch,純C語言,提供了非常多強大的函數。

GCD的優勢

  • GCD是蘋果公司為多核的并行運算提出的解決方案
  • GCD會自動利用更多的CPU內核(比如雙核、四核)
  • GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)
  • 程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼

2. 任務和隊列

GCD中有2個核心概念

  • 任務:執行什么操作
  • 隊列:用來存放任務

將任務添加到隊列中:

  • GCD會自動將隊列中的任務取出,放到對應的線程中執行
  • 任務的取出遵循隊列的FIFO原則:先進先出,后進后出

3. 執行任務

GCD中有2個用來執行任務的函數

  • 用同步的方式執行任務,queue:隊列  block:任務
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
  • 用異步的方式執行任務
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

同步和異步的區別

  • 同步:在當前線程中執行
  • 異步:在另一條線程中執行

4. 隊列的類型

GCD的隊列可以分為2大類型

  • 并發隊列(Concurrent Dispatch Queue):可以讓多個任務并發(同時)執行(自動開啟多個線程同時執行任務),并發功能只有在異步(dispatch_async)函數下才有效
  • 串行隊列(Serial Dispatch Queue):讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)

5. 并發隊列

GCD默認已經提供了全局的并發隊列,供整個應用使用,不需要手動創建

使用dispatch_get_global_queue函數獲得全局的并發隊列

dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, // 隊列的優先級unsigned long flags); // 此參數暫時無用,用0即可dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全局并發隊列

全局并發隊列的優先級

#define DISPATCH_QUEUE_PRIORITY_HIGH 2 //#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) //#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺

6. 串行隊列

GCD中獲得串行有2種途徑

使用dispatch_queue_create函數創建串行隊列

dispatch_queue_tdispatch_queue_create(const char *label, // 隊列名稱 dispatch_queue_attr_t attr); // 隊列屬性,一般用NULL即可dispatch_queue_t queue = dispatch_queue_create("queue", NULL); // 創建dispatch_release(queue); // 非ARC需要釋放手動創建的隊列

使用主隊列(跟主線程相關聯的隊列)

主隊列是GCD自帶的一種特殊的串行隊列

放在主隊列中的任務,都會放到主線程中執行

使用dispatch_get_main_queue()獲得主隊列

dispatch_queue_t queue = dispatch_get_main_queue();

7. 各種隊列的執行效果

8. 線程間通信示例

從子線程回到主線程

1 dispatch_async(2 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{3     // 執行耗時的異步操作...4       dispatch_async(dispatch_get_main_queue(), ^{5         // 回到主線程,執行UI刷新操作6         });7 });

9. 延時執行

iOS常見的延時執行有2種方式

  • 調用NSObject的方法

 

[self performSelector:@selector(run) withObject:nil afterDelay:2.0];// 2秒后再調用self的run方法

 

  • 使用GCD函數
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{    // 2秒后異步執行這里的代碼...});

10. 一次性代碼

使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1次

1 static dispatch_once_t onceToken;2 dispatch_once(&onceToken, ^{3     // 只執行1次的代碼(這里面默認是線程安全的)4 });

11. 隊列組

有這么1種需求

首先:分別異步執行2個耗時的操作

其次:等2個異步操作都執行完畢后,再回到主線程執行操作

 如果想要快速高效地實現上述需求,可以考慮用隊列組

 1 dispatch_group_t group =  dispatch_group_create(); 2 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3     // 執行1個耗時的異步操作 4 }); 5 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 6     // 執行1個耗時的異步操作 7 }); 8 dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 9     // 等前面的異步操作都執行完畢后,回到主線程...10 });

12. 單例模式

單例模式可以保證在程序運行過程,一個類只有一個實例,而且該實例易于供外界訪問。從而方便地控制了實例個數,并節約系統資源。

單例模式在ARC/MRC環境下的寫法有所不同,需要編寫2套不同的代碼

可以用宏判斷是否為ARC環境

#if __has_feature(objc_arc)// ARC#else// MRC#endif
  • 單例模式 - ARC

ARC中,單例模式的實現:

1. 在.m中保留一個全局的static的實例

static id _instance;

2. 重寫allocWithZone:方法,在這里創建唯一的實例(注意線程安全)

 

1 + (id)allocWithZone:(struct _NSZone *)zone2 {3     @synchronized(self) {4         if (!_instance) {5             _instance = [super allocWithZone:zone];6         }7     }8     return _instance;9 }

3. 提供1個類方法讓外界訪問唯一的實例

1 + (instancetype)sharedSoundTool2 {3     @synchronized(self) {4         if (!_instance) {5             _instance = [[self alloc] init];6         }7     }8     return _instance;9 }
  • 單例模式 – 非ARC

非ARC中(MRC),單例模式的實現(比ARC多了幾個步驟)

1. 實現copyWithZone:方法 

1 + (id)copyWithZone:(struct _NSZone *)zone2 {3     return _instance;4 }

2. 實現內存管理方法

1 - (id)retain { return self; }2 - (NSUInteger)retainCount { return 1; }3 - (oneway void)release {}4 - (id)autorelease { return self; }

 

四、NSOperation 

NSOperation的作用:

配合使用NSOperation和NSOperationQueue也能實現多線程編程

 

NSOperation和NSOperationQueue實現多線程的具體步驟:

  • 先將需要執行的操作封裝到一個NSOperation對象中
  • 然后將NSOperation對象添加到NSOperationQueue中
  • 系統會自動將NSOperation中封裝的操作放到一條新線程中執行

1. NSOperation的子類

NSOperation是個抽象類,并不具備封裝操作的能力,必須使用它的子類

使用NSOperation子類的方式有3種

  • NSInvocationOperation
  • NSBlockOperation
  • 自定義子類繼承NSOperation,實現內部相應的方法

NSInvocationOperation

創建NSInvocationOperation對象

- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;

調用start方法開始執行操作

- (void)start;

一旦執行操作,就會調用target的sel方法

注意:

  • 默認情況下,調用了start方法后并不會開一條新線程去執行操作,而是在當前線程同步執行操作
  • 只有將NSOperation放到一個NSOperationQueue中,才會異步執行操作

NSBlockOperation

創建NSBlockOperation對象

+ (id)blockOperationWithBlock:(void (^)(void))block;

通過addExecutionBlock:方法添加更多的操作

- (void)addExecutionBlock:(void (^)(void))block;

注意:只要NSBlockOperation封裝的操作數 > 1,就會異步執行操作

2. NSOperationQueue

NSOperationQueue的作用:NSOperation可以調用start方法來執行任務,但默認是同步執行的。如果將NSOperation添加到NSOperationQueue(操作隊列)中,系統會自動異步執行NSOperation中的操作。

添加操作到NSOperationQueue中

- (void)addOperation:(NSOperation *)op;- (void)addOperationWithBlock:(void (^)(void))block;

2.1 最大并發數

并發數也就是同時執行的任務數。比如,同時開3個線程執行3個任務,并發數就是3。

最大并發數的相關方法

- (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

3. 隊列的取消、暫停、恢復

取消隊列的所有操作

- (void)cancelAllOperations;

也可以調用NSOperation的- (void)cancel方法取消單個操作

暫停和恢復隊列

- (void)setSuspended:(BOOL)b; // YES代表暫停隊列,NO代表恢復隊列- (BOOL)isSuspended;

4. 操作優先級

設置NSOperation在queue中的優先級,可以改變操作的執行順序

- (NSOperationQueuePriority)queuePriority;- (void)setQueuePriority:(NSOperationQueuePriority)p;

優先級的取值(優先級越高,越先執行)

NSOperationQueuePriorityVeryLow = -8L,NSOperationQueuePriorityLow = -4L,NSOperationQueuePriorityNormal = 0,NSOperationQueuePriorityHigh = 4,NSOperationQueuePriorityVeryHigh = 8

5. 操作依賴

NSOperation之間可以設置依賴來保證執行順序,比如一定要讓操作A執行完后,才能執行操作B,可以這么寫:

[operationB addDependency:operationA]; // 操作B依賴于操作A

可以在不同queue的NSOperation之間創建依賴關系

注意:不能相互依賴,比如A依賴B,B依賴A

6. 操作的執行順序

對于添加到queue中的operations,它們的執行順序取決于2點:

  • 首先依據NSOperation之間的依賴關系
  • 然后依據NSOperation的優先級

因此,總體的執行順序是:先滿足依賴關系,然后再從NSOperation中選擇優先級最高的那個執行

7. 自定義NSOperation

自定義NSOperation的步驟很簡單

重寫- (void)main方法,在里面實現想執行的任務

 

重寫- (void)main方法的注意點

  • 自己創建自動釋放池(因為如果是異步操作,無法訪問主線程的自動釋放池)
  • 經常通過- (BOOL)isCancelled方法檢測操作是否被取消,對取消做出響應

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 砀山县| 资阳市| 宝兴县| 新余市| 株洲市| 洪泽县| 若尔盖县| 夏津县| 南京市| 改则县| 乐都县| 武强县| 广丰县| 确山县| 霸州市| 密云县| 呼玛县| 二连浩特市| 镇江市| 浮山县| 晋宁县| 通海县| 绍兴市| 石家庄市| 昌都县| 商丘市| 闸北区| 普格县| 正镶白旗| 霍州市| 张家港市| 达拉特旗| 保康县| 宜兰县| 诏安县| 綦江县| 阜南县| 九龙城区| 吉隆县| 丰城市| 肇源县|