iOS多執行緒的基本使用
一、NSThread:
程式就是一段程式碼,是靜態的概念
程序是執行起來的程式,是動態的概念,程序需要佔記憶體空間
執行緒是程序的基本單位,一個程序至少有一個執行緒,iOS程式預設有一個主執行緒,用來顯示和操作UI,主執行緒由系統自動建立,有系統管理。如果主執行緒不能滿足我們的需求,可以手動建立執行緒,手動建立的執行緒需要我們自己管理。
1.例:讓一個執行緒延遲10秒執行
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//按鈕一
UIButton *btn1 = [MyUtilcreateBtnFrame:CGRectMake(100,100, 80,40) title:@"按鈕一"bgImageName:niltarget:selfaction:@selector(clickBtnOne:)];
[self.viewaddSubview:btn1];
//按鈕二
UIButton *btn2 = [MyUtilcreateBtnFrame:CGRectMake(100,200, 80,40) title:@"按鈕二"bgImageName:niltarget:selfaction:@selector(clickBtnTwo:)];
[self.viewaddSubview:btn2];
}
- (void)clickBtnOne:(id)sender
{
//模擬耗時較長的操作
//例如實際中的網路請求或者資料庫的操作
//讓執行緒睡眠十秒
[NSThreadsleepForTimeInterval:10];
//如果不使用多執行緒,會有介面假死的現象
//使用者體驗不好
//所有在這種情況下我們需要使用多執行緒
}
- (void)clickBtnTwo:(id)sender
{
NSLog(@"%s",__func__);
}
2.執行緒的優先順序:
//用執行緒的這個屬性來修改執行緒的優先順序,屬性值越大,執行的次數越多
t1.threadPriority =0;
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//執行緒一
NSThread *t1 = [[NSThreadalloc] initWithTarget:selfselector:@selector(threadOne)object:nil];
//修改優先順序
//優先順序的值在0-1之間,優先順序越高,執行的次數相對來說會越多
t1.threadPriority =0;
[t1 start];
//執行緒二
NSThread *t2 = [[NSThreadalloc] initWithTarget:selfselector:@selector(threadTwo)object:nil];
//修改優先順序,線和二大於執行緒一,執行緒二先執行完成
t2.threadPriority =1;
[t2 start];
}
- (void)threadOne
{
for (int i=0; i<100; i++) {
NSLog(@"執行緒一:%d", i);
}
}
- (void)threadTwo
{
for (int i=0; i<100; i++) {
NSLog(@"執行緒二:%d", i);
}
}
3. 執行緒鎖:
第一種方法用: @synchronized加執行緒鎖
-(void)withDraw:(float)money
{
//多個執行緒修改同一塊資源的時候,會出現問題
//我們需要用執行緒鎖的方式解決
@synchronized(self){
if (_money >= money) {
//模擬取錢的時間
[NSThreadsleepForTimeInterval:1];
_money -= money;
NSLog(@"%@取了%f元",[NSThreadcurrentThread].name,money);
}else{
NSLog(@"餘額不足");
}
}
}
@end
第二種方法:
用NSLock 來實現加鎖和解鎖
@implementation MyAccount
{
//執行緒鎖
NSLock *_myLock;
}
-(instancetype)init
{
if (self = [superinit]) {
_myLock = [[NSLockalloc] init];
}
returnself;
}
-(void)withDraw:(float)money
{
//多個執行緒修改同一塊資源的時候,會出現問題
//我們需要用執行緒鎖的方式解決
//加鎖
[_myLocklock];
if (_money >= money) {
//模擬取錢的時間
[NSThreadsleepForTimeInterval:1];
_money -= money;
NSLog(@"%@取了%f元",[NSThreadcurrentThread].name,money);
}else{
NSLog(@"餘額不足");
}
//解鎖
[_myLockunlock];
}
@end
二:NSOpreation:
1.用NSOpreation實現線上下載圖片
#import "ViewController.h"
#import "ImageOperation.h"
@interfaceViewController ()
{
NSOperationQueue *_queue;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//建立圖片檢視
UIImageView *myImageView = [[UIImageViewalloc] initWithFrame:CGRectMake(40,100, 300,300)];
[self.viewaddSubview:myImageView];
//使用NSOperatio自定製型別實現多執行緒
//1.建立一個佇列
_queue = [[NSOperationQueuealloc] init];
//佇列裡面同時執行的執行緒最大數量
//例如往佇列裡面加了20個執行緒,只會執行10個,其他的執行緒要等這10箇中的某個執行完成之後,才能執行
_queue.maxConcurrentOperationCount =10;
//2.建立ImageOperation物件
ImageOperation *op = [[ImageOperationalloc] init];
//設定下載連結
op.urlString=@"http://g.hiphotos.baidu.com/image/pic/item/4034970a304e251fb3145e6ca586c9177e3e5346.jpg";
//設定顯示的檢視
op.imgView = myImageView;
//新增到佇列
[_queueaddOperation:op];
//ASIHttpRequest: NSOperation
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
#import "ImageOperation.h"
@implementation ImageOperation
//使用NSOperation自定製物件建立執行緒時的執行體
-(void)main
{
//下載圖片
NSURL *url = [NSURLURLWithString:self.urlString];
NSData *data = [NSDatadataWithContentsOfURL:url];
//回到主執行緒修改UI
[selfperformSelectorOnMainThread:@selector(refreshUI:)withObject:data waitUntilDone:YES];
}
- (void)refreshUI:(NSData *)data
{
self.imgView.image = [UIImageimageWithData:data];
}
@end
2.使用NSOperation建立多執行緒:
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//NSOperation實現多執行緒
//1.建立佇列
_queue = [[NSOperationQueuealloc] init];
//2.建立NSInvocationOperation物件
/*
第一個引數:執行緒執行體方法所屬的物件
第二個引數:執行緒執行體方法
第三個引數:執行緒執行體方法傳遞的實參
*/
NSInvocationOperation *op1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(threadOne)object:nil];
//執行緒結束之後執行的程式碼塊
[op1 setCompletionBlock:^{
NSLog(@"執行緒一結束");
}];
//3.開啟執行緒
[_queueaddOperation:op1];
//第二種實現執行緒的方式
NSBlockOperation *op2 = [NSBlockOperationblockOperationWithBlock:^{
//執行緒的執行體
for (int i=0; i<100; i++) {
NSLog(@"執行執行緒二:%d",i);
}
}];
//執行緒執行結束後呼叫的程式碼塊
[op2 setCompletionBlock:^{
NSLog(@"執行緒二結束");
}];
//新增到佇列裡面
[_queueaddOperation:op2];
}
//執行緒執行體方法
- (void)threadOne
{
for (int i=0; i<100; i++) {
NSLog(@"執行了執行緒一:%d", i);
}
}
三:GCD:
1.用GCD實現多執行緒:
#import "ViewController.h"
@interfaceViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//1.同一塊程式碼執行多次
//[self testApply];
//2.程式碼只執行一次
// [self testOnce];
// [self testOnce];
// [self testOnce];
// [self testOnce];
//3.在一段時間之後執行程式碼塊
//[self testAfter];
//4.執行緒組(group)
//[self testGroup];
//5.在某幾個執行緒都執行完成之後,並在另外幾個執行緒都執行完成之前,需要執行一些程式碼
[selftestBarrier];
}
//5.在某幾個執行緒都執行完成之後,並在另外幾個執行緒都執行完成之前,需要執行一些程式碼
- (void)testBarrier
{
//佇列不能是系統的全域性佇列
dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
//執行緒一
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"執行緒一:%d", i);
}
});
//執行緒二
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"執行緒二:%d", i);
}
});
//線上程一和執行緒二都執行完成之後,並且線上程三執行之前,呼叫一段程式碼塊
dispatch_barrier_async(concurrentQueue, ^{
NSLog(@"barrier");
});
//執行緒三
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"執行緒三:%d", i);
}
});
}
//4.多個執行緒都執行之後去執行一些程式碼
- (void)testGroup
{
//執行緒組
dispatch_group_t group =dispatch_group_create();
/*
第一個引數:執行緒組
第二個引數:執行緒所在的佇列
第三個引數:執行緒的執行體
*/
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
for (int i=0; i<100; i++) {
NSLog(@"執行了執行緒一:%d", i);
}
});
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
for (int i=0; i<100; i++) {
NSLog(@"執行了執行緒二:%d", i);
}
});
//在該組的所有執行緒都執行結束時做執行某段程式碼
dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSLog(@"所有執行緒都執行完成");
});
}
//3.在一段時間之後執行程式碼塊
- (void)testAfter
{
NSLog(@"執行之前");
//DISPATCH_TIME_NOW:表示當前的時間
//當前時間的十秒之後
dispatch_time_t myTime =dispatch_time(DISPATCH_TIME_NOW,NSEC_PER_SEC*10);
//佇列
//建立一個並行的佇列
dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
/*
第一個引數:程式碼塊執行的時間
第二個引數:程式碼塊的執行緒所在的佇列
第三個引數:執行的程式碼塊
*/
dispatch_after(myTime, concurrentQueue, ^{
NSLog(@"執行了程式碼塊");
});
}
//2.程式碼只執行一次
//通常用來實現單例
- (void)testOnce
{
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"執行了一次");
});
}
//1.同一塊程式碼執行多次
- (void)testApply
{
/*
第一個引數:程式碼塊執行多少次
第二個引數:執行緒所在的佇列
第三個引數:執行緒的執行體
*/
dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//引數表示當前是第幾次執行
dispatch_apply(10, globalQueue, ^(size_t time) {
//執行緒的執行體
NSLog(@"執行到了第%ld次", time);
});
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
2.GCD實現多執行緒2:
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//GCD實現多執行緒
//一、GCD的佇列
//1.主執行緒所在的序列佇列
//系統自動建立了這個佇列,我們只要獲取後使用
dispatch_queue_t mainQueue =dispatch_get_main_queue();
//2.系統的全域性並行佇列
//系統自動建立了這個佇列,我們只能獲取後使用
/*
第一個引數:佇列的優先順序
第二個引數:APPLE公司保留的引數
*/
dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//3.自己建立的佇列
//1)序列佇列
/*
第一個引數:佇列的識別符號
第二個引數:用來區分是序列佇列還是並行佇列
DISPATCH_QUEUE_SERIAL:序列佇列
DISPATCH_QUEUE_CONCURRENT:並行佇列
*/
dispatch_queue_t serialQueue =dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);
//2)並行佇列
dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
//二、GCD建立執行緒
//1、非同步將執行緒的執行體程式碼放到佇列執行
/*
第一個引數:佇列
第二個引數:執行緒的執行體程式碼
*/
dispatch_queue_t queueOne =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queueOne, ^{
for (int i=0; i<100; i++) {
NSLog(@"執行了執行緒一:%d", i);
}
});
//2、同步將執行緒的執行體放到佇列執行
dispatch_sync(queueOne, ^{
for (int i=0; i<100; i++) {
NSLog(@"執行了執行緒二:%d", i);
}
});
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];