進(jìn)程
線程
執(zhí)行完上一個才能執(zhí)行下一個
)多線程
多線程原理
多線程優(yōu)缺點(diǎn)
程序設(shè)計(jì)更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享
/*參數(shù):1. 線程代號的地址2. 線程的屬性3. 調(diào)用函數(shù)的指針 - void *(*)(void *) - 返回值 (函數(shù)指針)(參數(shù)) - void * 和 OC 中的 id 是等價的4. 傳遞給該函數(shù)的參數(shù)返回值:如果是0,表示正確如果是非0,表示錯誤碼*/NSString *str = @"jx";pthread_t thid;int res = pthread_create(&thid, NULL, &demo, (__bridge void *)(str));if (res == 0) { NSLog(@"OK");} else { NSLog(@"error %d", res);}
NSThread
創(chuàng)建線程的幾種方式
// 1.創(chuàng)建線程 NJThread *thread = [[NJThread alloc] initWithTarget:self selector:@selector(demo:) object:@"jx"]; // 設(shè)置線程名稱 [thread setName:@"ljx"]; // 設(shè)置線程的優(yōu)先級 // 優(yōu)先級僅僅說明被CPU調(diào)用的可能性更大 [thread setThreadPRiority:1.0]; // 2.啟動線程 [thread start];
- detach/performSelector + 優(yōu)點(diǎn):簡單快捷 + 缺點(diǎn):無法對線程進(jìn)行更詳細(xì)的設(shè)置```objc// 1.創(chuàng)建線程[NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"jx"];// 1.創(chuàng)建線程// 注意: Swift中不能使用, 蘋果認(rèn)為這個方法不安全 [self performSelectorInBackground:@selector(demo:) withObject:@"jx"];
啟動線程 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];[thread start]; // 進(jìn)入就緒狀態(tài) -> 運(yùn)行狀態(tài)。當(dāng)線程任務(wù)執(zhí)行完畢,自動進(jìn)入死亡狀態(tài) 阻塞(暫停)線程 + (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti; // 進(jìn)入阻塞狀態(tài) 強(qiáng)制停止線程 + (void)exit; // 進(jìn)入死亡狀態(tài)注意:一旦線程停止(死亡)了,就不能再次開啟任務(wù) 如圖:
多線程的安全隱患
@synchronized(鎖對象) { // 需要鎖定的代碼 }
互斥鎖的優(yōu)缺點(diǎn) 優(yōu)點(diǎn):能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題 缺點(diǎn):需要消耗大量的CPU資源
互斥鎖注意點(diǎn)
原子和非原子屬性
自旋鎖 & 互斥鎖
#import "ViewController.h"@interface ViewController ()@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation ViewController- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ // 開啟一個子線程下載圖片 [self performSelectorInBackground:@selector(downlod) withObject:nil];}- (void)downlod{ NSLog(@"%@", [NSThread currentThread]); // 1.下載圖片 NSURL *url = [NSURL URLWithString:@"http://pic.4j4j.cn/upload/pic/20130531/07ed5ea485.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; // 2.將二進(jìn)制轉(zhuǎn)換為圖片 UIImage *image = [UIImage imageWithData:data]; // 3.跟新UI#warning 注意: 千萬不要在子線程中更新UI, 會出問題 /* waitUntilDone: YES: 如果傳入YES, 那么會等待updateImage方法執(zhí)行完畢, 才會繼續(xù)執(zhí)行后面的代碼 NO: 如果傳入NO, 那么不會等待updateImage方法執(zhí)行完畢, 就可以繼續(xù)之后后面的代碼 */ /* [self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:NO]; */ // 開發(fā)中常用// [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; // 可以在指定的線程中, 調(diào)用指定對象的指定方法 [self performSelector:@selector(updateImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES]; }- (void)updateImage:(UIImage *)image{ NSLog(@"%@", [NSThread currentThread]); // 3.更新UI self.imageView.image = image; }
GCD中有2個核心概念
執(zhí)行任務(wù)
隊(duì)列
GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個應(yīng)用使用,可以無需手動創(chuàng)建 使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列 dispatch_queue_t dispatch_get_global_queue( dispatch_queue_priority_t priority, // 隊(duì)列的優(yōu)先級 unsigned long flags); // 此參數(shù)暫時無用,用0即可 獲得全局并發(fā)隊(duì)列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 全局并發(fā)隊(duì)列的優(yōu)先級 #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中) #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺
串行隊(duì)列 * 讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù))
GCD中獲得串行有2種途徑 使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列 // 創(chuàng)建串行隊(duì)列(隊(duì)列類型傳遞NULL或者DISPATCH_QUEUE_SERIAL) dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", NULL); 使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列) 主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列 放在主隊(duì)列中的任務(wù),都會放到主線程中執(zhí)行 使用dispatch_get_main_queue()獲得主隊(duì)列 dispatch_queue_t queue = dispatch_get_main_queue();
注意點(diǎn)
同步和異步主要影響:能不能開啟新的線程各種任務(wù)隊(duì)列搭配
GCD線程間通信
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執(zhí)行耗時的異步操作... dispatch_async(dispatch_get_main_queue(), ^{ // 回到主線程,執(zhí)行UI刷新操作 });});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后執(zhí)行這里的代碼...});
一次性代碼
程序運(yùn)行過程中
只被執(zhí)行1次static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的) });
快速迭代
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){ // 執(zhí)行10次代碼,index順序不確定});
不能是全局的并發(fā)隊(duì)列
所有的任務(wù)都必須在一個隊(duì)列中
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
dispatch_group_t group = dispatch_group_create();dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執(zhí)行1個耗時的異步操作});dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執(zhí)行1個耗時的異步操作});dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 等前面的異步操作都執(zhí)行完畢后,回到主線程...});
iOS中多線程的實(shí)現(xiàn)方案
單例模式
單例模式的作用
- 可以保證在程序運(yùn)行過程,一個類只有一個實(shí)例,而且該實(shí)例易于供外界訪問,從而方便地控制了實(shí)例個數(shù),并節(jié)約系統(tǒng)資源
單例模式的使用場合
ARC中,單例模式的實(shí)現(xiàn)
在.m中保留一個全局的static的實(shí)例 static id _instance; 重寫allocWithZone:方法,在這里創(chuàng)建唯一的實(shí)例(注意線程安全) + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ _instance = [super allocWithZone:zone]; }); return _instance; } 提供1個類方法讓外界訪問唯一的實(shí)例 + (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } 實(shí)現(xiàn)copyWithZone:方法 - (id)copyWithZone:(struct _NSZone *)zone { return _instance; } 注意點(diǎn) // 注意點(diǎn): 單例是不可以繼承的, 如果繼承引發(fā)問題 // 如果先創(chuàng)建父類, 那么永遠(yuǎn)都是父類 // 如果先創(chuàng)建子類, 那么永遠(yuǎn)都是子類
|
新聞熱點(diǎn)
疑難解答
圖片精選