一添吗、多線程概述
一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí)就成了一個(gè)進(jìn)程,一個(gè)進(jìn)程包含若干線程,其中必有一個(gè)主線程.線程之間運(yùn)行是獨(dú)立的.
多線程優(yōu)勢(shì)
- 線程之間容易共享內(nèi)存,進(jìn)程間不能.
- 充分發(fā)揮多核處理器的優(yōu)勢(shì),不同任務(wù)分配給不同處理器,進(jìn)入“并行運(yùn)算”的狀態(tài)
- 將耗時(shí)、輪詢或并發(fā)需求高的任務(wù)分配到其他線程進(jìn)行,主線程負(fù)責(zé)統(tǒng)一更新界面,這樣使用戶體驗(yàn)更好.
- 多線程劣勢(shì)
- 占內(nèi)存(默認(rèn)住線程1M 子線程512K)
- CPU開(kāi)銷大(一般同時(shí)開(kāi)啟線程小于5個(gè)).
- 程序設(shè)計(jì)變得復(fù)雜.
- 多線程狀態(tài)
1.新建(New):分配內(nèi)存,初始化內(nèi)部成員變量的值
2.就緒(Runable):創(chuàng)建方法調(diào)用的棧和計(jì)數(shù)器
3.運(yùn)行(Running):運(yùn)行狀態(tài)
4.終止(Exit):線程終止
5.阻塞(Blocked):線程需要暫停一段時(shí)間
二潜圃、iOS多線程技術(shù)
pthread
1.跨平臺(tái),可移植
2.使用難度大
3.C語(yǔ)言NSThread
1.面向?qū)ο?br> 2.直接操作線程對(duì)象
3.Objective-CGCD
1.替代NSThread
2.充分利用多核技術(shù)
3.C語(yǔ)言NSOperation
1.基于GCD,更簡(jiǎn)單
2.更面向?qū)ο?br> 3.Objective-C
三箱吕、NSThread三種創(chuàng)建線程的方法及阻塞線程的測(cè)試
在storyboard里放一個(gè)Button和一個(gè)Text View(用來(lái)測(cè)試線程的阻塞)
- 線程一啟動(dòng)就會(huì)執(zhí)行
self
的run:
方法 - 測(cè)試阻塞線程時(shí),由于
test
方法處在主線程,Debug欄一直輸出,所以拖動(dòng)文本視圖沒(méi)有任何反應(yīng).
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//獲取當(dāng)前芥驳、主線程
- (IBAction)ClickBtn:(id)sender {
NSThread *current = [NSThread currentThread];
NSLog(@"Current thread %@ ",current);
NSThread *main = [NSThread mainThread];
NSLog(@"Main thread %@",main);
[self threadCreate1];
//第二種方法 [self threadCreate2];
//第三種方法 [self threadCreate3];
//測(cè)試阻塞方法 [self threadTest];
}
//輸出當(dāng)前線程
- (void)run:(NSString *)param{
NSThread *current = [NSThread currentThread];
for(int i = 0; i<10; i++){
NSLog(@"%@ run %@",current,param);
}
}
- (void)threadCreate1{
NSThread *threadA =[[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"線程A參數(shù)"];
threadA.name = @"線程A";
[threadA start];
NSThread *threadB =[[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"線程B參數(shù)"];
threadB.name = @"線程B";
[threadB start];
}
- (void)threadCreate2{
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"方式2參數(shù)"];
}
//隱式創(chuàng)建并啟動(dòng)線程,在后臺(tái)線程中執(zhí)行
- (void)threadCreate3{
[self performSelectorInBackground:@selector(run:) withObject:@"方式3參數(shù)"];
}
//測(cè)試阻塞線程
- (void)threadTest{
NSLog(@"%@",[NSThread currentThread]);
for (int i=0 ; i<10000; i++) {
NSLog(@"-----%d",i);
}
}
@end
四、線程間的安全隱患
- 線程共享會(huì)造成資源搶奪,引起數(shù)據(jù)錯(cuò)亂及安全問(wèn)題
- 使用
@synchronized(obj)
修飾同步代碼塊
五茬高、線程間的通信
- 主線程的方法
performSelectorOnMainThread:(SEL) withObject:(id) waitUntilDone:(BOOL)
- 子線程的方法
performSelector:(SEL) onThread:(NSThread *) withObject:(id) waitUntilDone:(BOOL)
GCD(Grand Central Dispatch)
- 基于C語(yǔ)言
- 系統(tǒng)完全管理線程, 無(wú)需編寫線程代碼
一兆旬、隊(duì)列(Dispatch Queue)
- 將長(zhǎng)期運(yùn)行任務(wù)(代碼塊)拆成多個(gè)工作單元并添加到隊(duì)列中,系統(tǒng)代為管理并放到多個(gè)線程上執(zhí)行
- FIFO(先進(jìn)先出)原則,先進(jìn)隊(duì)列先處理,但由于執(zhí)行時(shí)間不同,不一定先結(jié)束
- 分類:
1.Serial Dispatch Queue(串行隊(duì)列): 底層線程池只有一個(gè)線程,一次執(zhí)行一個(gè)任務(wù),執(zhí)行完一個(gè)任務(wù)才能執(zhí)行下一個(gè)
2.Concurrent Dispatch Queue(并行隊(duì)列): 底層線程池有多個(gè)線程,按FIFO原則執(zhí)行多任務(wù)
二、創(chuàng)建隊(duì)列
1.獲取全局并發(fā)隊(duì)列(Global Concurrent Dispatch Queue)
- 全局并發(fā)隊(duì)列可以按FIFO順序并行執(zhí)行多個(gè)任務(wù)
- 用
dispatch_get_global_queue(long identifier, unsigned long flags)
獲取隊(duì)列
第一個(gè)參數(shù)用于指定隊(duì)列優(yōu)先級(jí),含4個(gè)宏定義常量:
#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 //后臺(tái)
2.創(chuàng)建串怎栽、并行隊(duì)列(Serial And Concurrent Dispatch Queue)
- 創(chuàng)建隊(duì)列
dispatch_queue_t
dispatch_queue_create(const char * label, dispatch_queue_attr_t attr)
第一個(gè)參數(shù)表示隊(duì)列的字符串
第二個(gè)參數(shù)控制串并發(fā)隊(duì)列(設(shè)為NULL默認(rèn)串行):
DISPATCH_QUEUE_SERIAL //串行
DISPATCH_QUEUE_CONCURRENT //并行
3.獲取主隊(duì)列
- 主隊(duì)列在主線程中執(zhí)行
- 用
dispatch_get_main_queue()
獲取主隊(duì)列
三丽猬、提交任務(wù)
1.同步添加任務(wù)到隊(duì)列,不具備開(kāi)啟新線程能力,阻塞調(diào)用線程直到相應(yīng)任務(wù)完成
- 調(diào)用函數(shù)
dispatch_sync(dispatch_queue_t queue, ^(void)block) //代碼塊
dispatch_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work) //函數(shù)
2.異步在新線程執(zhí)行任務(wù),可以讓線程池立即執(zhí)行,調(diào)用其他線程做其他事情,應(yīng)盡可能使用異步.
- 調(diào)用函數(shù):
dispatch_async(dispatch_queue_t queue, ^(void)block) //代碼塊
dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work) //函數(shù)
- 在storyboard放兩個(gè)Button分別執(zhí)行串、并行任務(wù)
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
dispatch_queue_t serialQueue;
dispatch_queue_t globalQueue;
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建串行隊(duì)列
serialQueue = dispatch_queue_create("serQ", DISPATCH_QUEUE_SERIAL);
//全局并發(fā)隊(duì)列
globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
//串行異步執(zhí)行任務(wù)
- (IBAction)asynSerial:(id)sender {
dispatch_async(serialQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task1 %d",[NSThread currentThread],i);
}
});
dispatch_async(serialQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task2 %d",[NSThread currentThread],i);
}
});
}
//并行異步執(zhí)行任務(wù)
- (IBAction)asynConcurrent:(id)sender {
dispatch_async(globalQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task1 %d",[NSThread currentThread],i);
}
});
dispatch_async(globalQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"%@ task2 %d",[NSThread currentThread],i);
}
});
}
@end
四婚瓜、單次或重復(fù)執(zhí)行任務(wù)
- 單次執(zhí)行
dispatch_once(dispatch_once_t * predicate, ^(void)block)
- 多次執(zhí)行
dispatch_apply(size_t iterations, dispatch_queue_t queue, ^(size_t)block)
五宝鼓、調(diào)度隊(duì)列組
- 將多個(gè)block組成一組,監(jiān)聽(tīng)此組任務(wù)是否全部完成.
1.創(chuàng)建隊(duì)列組對(duì)象dispatch_group_create()
2.調(diào)度隊(duì)列組dispatch_group_async()
3.通知:任務(wù)執(zhí)行完后通知執(zhí)行其他操作dispatch_group_notify()
NSOperation
- NSOperation實(shí)例代表一個(gè)多線程任務(wù)
新建一個(gè)繼承NSOperation的類.
//Download.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class Download;
//定義代理
@protocol DownloadDelegate <NSObject>
//下載方法
- (void)download:(Download *)operation image:(UIImage *)image;
@end
@interface Download : NSOperation
@property (nonatomic, strong)NSString *url;
//代理屬性
@property (nonatomic, weak)id<DownloadDelegate>delegate;
@end
//Download.m
#import "Download.h"
@implementation Download
//重寫main方法
- (void)main
{
@autoreleasepool {
NSURL *url = [NSURL URLWithString:self.url];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
NSLog(@"download finished");
if ([self.delegate respondsToSelector:@selector(download:image:)]) {
[self.delegate download:self image:image];
}
}];
}
}
@end
在storyboard中放一個(gè)Image View
//ViewController.m
#import "ViewController.h"
#import "Download.h"
@interface ViewController ()<DownloadDelegate>
@property (strong, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//下載操作
Download *operation = [[Download alloc]init];
operation.delegate = self;
operation.url =@"https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/943ff442182699.57c4298d2eb2a.png" ;
//操作加到隊(duì)列中
[queue addOperation:operation];
}
//執(zhí)行操作
- (void)download:(Download *)operation image:(UIImage *)image{
self.imageView.image = image;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
若提示:
App Transport security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
解決方法: