進程安全
線程多線程
執行完上一個才能執行下一個
)多線程併發
多線程原理app
多線程優缺點異步
程序設計更加複雜:好比線程之間的通訊、多線程的數據共享
/* 參數: 1. 線程代號的地址 2. 線程的屬性 3. 調用函數的指針 - void *(*)(void *) - 返回值 (函數指針)(參數) - void * 和 OC 中的 id 是等價的 4. 傳遞給該函數的參數 返回值: 若是是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); }
NSThreadasync
建立線程的幾種方式函數
// 1.建立線程 NJThread *thread = [[NJThread alloc] initWithTarget:self selector:@selector(demo:) object:@"jx"]; // 設置線程名稱 [thread setName:@"ljx"]; // 設置線程的優先級 // 優先級僅僅說明被CPU調用的可能性更大 [thread setThreadPriority:1.0]; // 2.啓動線程 [thread start];
- detach/performSelector + 優勢:簡單快捷 + 缺點:沒法對線程進行更詳細的設置 ```objc // 1.建立線程 [NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"jx"]; // 1.建立線程 // 注意: Swift中不能使用, 蘋果認爲這個方法不安全 [self performSelectorInBackground:@selector(demo:) withObject:@"jx"];
啓動線程 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [thread start]; // 進入就緒狀態 -> 運行狀態。當線程任務執行完畢,自動進入死亡狀態 阻塞(暫停)線程 + (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti; // 進入阻塞狀態 強制中止線程 + (void)exit; // 進入死亡狀態 注意:一旦線程中止(死亡)了,就不能再次開啓任務 如圖:
多線程的安全隱患性能
@synchronized(鎖對象) { // 須要鎖定的代碼 }
互斥鎖的優缺點 優勢:能有效防止因多線程搶奪資源形成的數據安全問題 缺點:須要消耗大量的CPU資源atom
互斥鎖注意點url
原子和非原子屬性
自旋鎖 & 互斥鎖
#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.將二進制轉換爲圖片 UIImage *image = [UIImage imageWithData:data]; // 3.跟新UI #warning 注意: 千萬不要在子線程中更新UI, 會出問題 /* waitUntilDone: YES: 若是傳入YES, 那麼會等待updateImage方法執行完畢, 纔會繼續執行後面的代碼 NO: 若是傳入NO, 那麼不會等待updateImage方法執行完畢, 就能夠繼續以後後面的代碼 */ /* [self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:NO]; */ // 開發中經常使用 // [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; // 能夠在指定的線程中, 調用指定對象的指定方法 [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個核心概念
執行任務
隊列
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 // 後臺
串行隊列 * 讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務)
GCD中得到串行有2種途徑 使用dispatch_queue_create函數建立串行隊列 // 建立串行隊列(隊列類型傳遞NULL或者DISPATCH_QUEUE_SERIAL) dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", NULL); 使用主隊列(跟主線程相關聯的隊列) 主隊列是GCD自帶的一種特殊的串行隊列 放在主隊列中的任務,都會放到主線程中執行 使用dispatch_get_main_queue()得到主隊列 dispatch_queue_t queue = dispatch_get_main_queue();
注意點
同步和異步主要影響:能不能開啓新的線程各類任務隊列搭配
GCD線程間通訊
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執行耗時的異步操做... dispatch_async(dispatch_get_main_queue(), ^{ // 回到主線程,執行UI刷新操做 }); });
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒後執行這裏的代碼... });
一次性代碼
程序運行過程當中
只被執行1次static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 只執行1次的代碼(這裏面默認是線程安全的) });
快速迭代
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){ // 執行10次代碼,index順序不肯定 });
不能是全局的併發隊列
全部的任務都必須在一個隊列中
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), ^{ // 執行1個耗時的異步操做 }); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 執行1個耗時的異步操做 }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 等前面的異步操做都執行完畢後,回到主線程... });
iOS中多線程的實現方案
單例模式
單例模式的做用
- 能夠保證在程序運行過程,一個類只有一個實例,並且該實例易於供外界訪問,從而方便地控制了實例個數,並節約系統資源
單例模式的使用場合
ARC中,單例模式的實現
在.m中保留一個全局的static的實例 static id _instance; 重寫allocWithZone:方法,在這裏建立惟一的實例(注意線程安全) + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ _instance = [super allocWithZone:zone]; }); return _instance; } 提供1個類方法讓外界訪問惟一的實例 + (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } 實現copyWithZone:方法 - (id)copyWithZone:(struct _NSZone *)zone { return _instance; } 注意點 // 注意點: 單例是不能夠繼承的, 若是繼承引起問題 // 若是先建立父類, 那麼永遠都是父類 // 若是先建立子類, 那麼永遠都是子類