iOS多線程

iOS多線程實現(xiàn)方案

多線程實現(xiàn)方案.png

GCD(Grand Central Dispatch)

一、基本用法
GCD會自動利用更多的CPU內(nèi)核(比如雙核、四核)。
GCD會自動管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程)。
只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼。

01 異步函數(shù)+并發(fā)隊列:開啟多條線程,并發(fā)執(zhí)行任務(wù) //start end...在多條線程
02 異步函數(shù)+串行隊列:開啟一條線程,串行執(zhí)行任務(wù)//start end...為串行隊列開啟一個線程
03 同步函數(shù)+并發(fā)隊列:不開線程,串行執(zhí)行任務(wù) //start...end在當前線程 
04 同步函數(shù)+串行隊列:不開線程,串行執(zhí)行任務(wù)//start...end在當前線程 
05 異步函數(shù)+主隊列:不開線程,在主線程中串行執(zhí)行任務(wù)//start end...主隊列:在主線程執(zhí)行
06 同步函數(shù)+主隊列:不開線程,串行執(zhí)行任務(wù)(注意死鎖發(fā)生)
07 使用sync函數(shù)往當前串行隊列中添加任務(wù),會卡住當前的(線程.)串行隊列
GCD.png
  • 例子: 異步+串行隊列
NSLog(@"----start-%@" , [NSThread currentThread]);
dispatch_queue_t queue1 =  dispatch_queue_create("download1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 =  dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue2, ^{
          NSLog(@"---queue2222---%@",[NSThread currentThread]);
      });
dispatch_async(queue1, ^{
    NSLog(@"---download1---%@",[NSThread currentThread]);
});
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"---download2---%@",[NSThread currentThread]);
});
dispatch_async(queue1, ^{
    NSLog(@"---download3---%@",[NSThread currentThread]);
});
dispatch_async(queue1, ^{
    NSLog(@"---download4---%@",[NSThread currentThread]);
});
NSLog(@"----end-%@", [NSThread currentThread]);
//----start-<NSThread: 0x60000018cd80>{number = 1, name = main}
//----end-<NSThread: 0x60000018cd80>{number = 1, name = main}
//---download1---<NSThread: 0x6000001863c0>{number = 6, name = (null)}
//---queue2222---<NSThread: 0x6000001c4100>{number = 5, name = (null)}
//---download3---<NSThread: 0x6000001863c0>{number = 6, name = (null)}
//---download2---<NSThread: 0x60000018cd80>{number = 1, name = main}
//---download4---<NSThread: 0x6000001863c0>{number = 6, name = (null)}
  • 例子2:死鎖
//使用sync往主隊列加任務(wù)并不一定死鎖。
//在子線程的當前串行隊列繼續(xù)加任務(wù)也會死鎖。
dispatch_async(dispatch_queue_create("q", DISPATCH_QUEUE_SERIAL), ^{
        NSLog(@"-----%@",[NSThread currentThread]);
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"不會死鎖===%@",[NSThread currentThread]);
        });
        dispatch_sync(dispatch_get_current_queue(), ^{
             NSLog(@"會死鎖-----%@",[NSThread currentThread]);
        });
    });
 //-----<NSThread: 0x6000036db1c0>{number = 6, name = (null)}
 //不會死鎖===<NSThread: 0x6000036dcec0>{number = 1, name = main}
//卡死

二、其他方法

  • dispatch_group_t隊列組 dispatch_group_async dispatch_group_notify
    只能保證執(zhí)行當前線程任務(wù)完成后notify,不能保證二級任務(wù)
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t q = dispatch_get_global_queue(0, 0); 
dispatch_group_async(group, q, ^{
          for(NSInteger i = 0; i < 100; i++)
          {
              NSLog(@"++++%ld", (long)i);
          }
        
        dispatch_async(q, ^{

            for(NSInteger i = 0; i < 200; i++)
            {
                NSLog(@"-----%ld", (long)i);
            }
        });
  });
 dispatch_group_notify(group, q, ^{
        NSLog(@"======");
  });
//++++99
//-----0
//======
//-----1
  • dispatch_group_enter dispatch_group_leave 可以保證子任務(wù)
dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_enter(group);
      for(NSInteger i = 0; i < 100; i++)
      {
          NSLog(@"++++%ld", (long)i);
      }
    dispatch_group_leave(group);

    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        for(NSInteger i = 0; i < 200; i++)
        {
            NSLog(@"-----%ld", (long)i);
        }
        dispatch_group_leave(group);//寫在async函數(shù)里才可
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"======");
    });
  • dispatch_barrier_async柵欄函數(shù),用來控制并發(fā)隊列的執(zhí)行順序
  • dispatch_after延遲執(zhí)行
//表名2秒鐘之后調(diào)用run
//    [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
//    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    /*
     第一個參數(shù):延遲時間
     第二個參數(shù):要執(zhí)行的代碼
     */
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        NSLog(@"---%@",[NSThread currentThread]);
    });
  • dispatch_once_t整個程序運行后只執(zhí)行一次
static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{   
    });
  • dispatch_apply創(chuàng)建多條線程執(zhí)行
//創(chuàng)建隊列(并發(fā)隊列)
dispatch_queue_t queue = dispatch_queue_create("com.downloadqueue", DISPATCH_QUEUE_CONCURRENT);
/*
 第一個參數(shù):迭代的次數(shù)
 第二個參數(shù):在哪個隊列中執(zhí)行
 第三個參數(shù):block要執(zhí)行的任務(wù)
 */
dispatch_apply(10, queue, ^(size_t index) {
    NSLog(@"%zd--%@",index,[NSThread currentThread]);
});

//文件在哪個地方(文件夾)
NSString *form = @"/Users/xiaomage/Desktop/form";
//要剪切到什么地方
NSString *to = @"/Users/xiaomage/Desktop/to";
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *subpaths =  [manager subpathsAtPath:form];
//NSDirectoryEnumerator *enumer = [manager enumeratorAtPath:to];//可以打印嵌套文件夾下文件路徑
//NSDirectoryEnumerator *enumer = [manager contentsOfDirectoryAtPath:to error:nil]; 
//for (NSDirectoryEnumerator *en in enumer) {
//        NSLog(@"%@",en);
//  }
//    NSLog(@"%@",subpaths);
NSInteger count = [subpaths count];
for (NSInteger i = 0; i<count; i++) {
    //拼接文件全路徑
//        NSString *fullPath = [form stringByAppendingString:<#(nonnull NSString *)#>]
    NSString *subpath = subpaths[i];
    NSString *fullPath = [form stringByAppendingPathComponent:subpath];
    //拼接目標文件全路徑
    NSString *fileName = [to stringByAppendingPathComponent:subpath];
    //剪切操作
    [manager moveItemAtPath:fullPath toPath:fileName error:nil];
    NSLog(@"%@--%@",fullPath,fileName);
}

NSOperationQueue

一、NSOperation

  • NSInvocationOperation
 /*
     第一個參數(shù):目標對象
     第二個參數(shù):選擇器,要調(diào)用的方法
     第三個參數(shù):方法要傳遞的參數(shù)
     */
    //    NSInvocationOperation *op  = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil];
    //
    //    //啟動操作
    //    [op start];
  • NSBlockOperation
 //1.封裝操作//在主線程
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1------%@",[NSThread currentThread]);
    }];
    
//2.追加操作//在子線程中并發(fā)執(zhí)行
    [op1 addExecutionBlock:^{
        NSLog(@"2------%@",[NSThread currentThread]);
    }];
    [op1 addExecutionBlock:^{
        NSLog(@"3------%@",[NSThread currentThread]);
    }];
  • 寫一個類繼承NSOperation,重新main方法。[op start];時調(diào)用main方法。

二、 NSOperationQueue

1.將操作放入,系統(tǒng)自動異步執(zhí)行
  • NSInvocationOperation添加到操作隊列
/*
 主隊列:凡是放到主隊列里面的任務(wù)都在主線程執(zhí)行[NSOperationQueue mainQueue]
 非主隊列:alloc int,同時具備了并發(fā)和串行的功能,默認是并發(fā)隊列
 */
//1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download2) object:nil];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download3) object:nil];

//3.添加操作到隊列,系統(tǒng)自動異步執(zhí)行
[queue addOperation:op1];   //[op1 start]
[queue addOperation:op2];
[queue addOperation:op3];

-(void)download1
{
    NSLog(@"download1---%@",[NSThread currentThread]);
}
  • NSBlockOperation添加到操作隊列
 //1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"1----%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"2----%@",[NSThread currentThread]);
}];
[op2 addExecutionBlock:^{
    NSLog(@"3----%@",[NSThread currentThread]);
}];
//3.添加操作到隊列
[queue addOperation:op1];   //[op1 start]
[queue addOperation:op2];
//簡便方法
[queue addOperationWithBlock:^{
     NSLog(@"4----%@",[NSThread currentThread]);
}];
  • 繼承類類型
//1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作
XMGOperation *op1 = [[XMGOperation alloc]init];
XMGOperation *op2 = [[XMGOperation alloc]init];
//3.添加操作到隊列
[queue addOperation:op1];   //[op1 start]
[queue addOperation:op2];
2.其他
  • maxConcurrentOperationCount
    默認是最大并發(fā)數(shù)-1是并發(fā)隊列,如果最大并發(fā)數(shù)>1,并發(fā)
    如果最大并發(fā)數(shù)==1,串行隊列(也可能有多個線程)
  • suspended YES暫停NO恢復(fù)
    只能暫停隊列中后面的操作,不能暫停正在執(zhí)行的操作。
  • cancelAllOperations 取消,不再執(zhí)行 operation.isCancelled判斷操作是否已取消
  • 操作監(jiān)聽和依賴
//1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSOperationQueue *queue1 = [[NSOperationQueue alloc]init];
//2.封裝操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"1----%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"2----%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"3----%@",[NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"4----%@",[NSThread currentThread]);
}];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
    for (NSInteger i=0; i<1000; i++) {
        NSLog(@"5-%zd---%@",i,[NSThread currentThread]);
    }
}];
op4.completionBlock = ^{
    NSLog(@"op4已經(jīng)完成了---%@",[NSThread currentThread]);
};

//添加操作依賴,注意不能循環(huán)依賴
//也可以依賴其他隊列的操作
[op1 addDependency:op5];
[op1 addDependency:op4];

//添加操作到隊列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue1 addOperation:op5];
  • 線程間通信
//1.創(chuàng)建隊列
NSOperationQueue *queue= [[NSOperationQueue alloc]init];
//2.下載圖片
[queue addOperationWithBlock:^{
    //2.1.確定要下載網(wǎng)絡(luò)圖片的url地址,一個url唯一對應(yīng)著網(wǎng)絡(luò)上的一個資源
    NSURL *url = [NSURL URLWithString:@"http://p6.qhimg.com/t01d2954e2799c461ab.jpg"];
    //2.2.根據(jù)url地址下載圖片數(shù)據(jù)到本地(二進制數(shù)據(jù))
    NSData *data = [NSData dataWithContentsOfURL:url];
    //2.3.把下載到本地的二進制數(shù)據(jù)轉(zhuǎn)換成圖片
    UIImage *image = [UIImage imageWithData:data];
    //3.回到主線程刷新UI
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        self.imageView.image = image;
        NSLog(@"%@----",[NSThread currentThread]);
    }];
}];

NSThread

/*
 第一個參數(shù):目標對象
 第二個參數(shù):選擇器,調(diào)用哪個方法
 第三個參數(shù):前面方法需要傳遞的參數(shù)
 */
NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil];
//設(shè)置基本屬性
thread1.name = @"線程1";
//線程優(yōu)先級
[thread1 setThreadPriority:1.0];//默認0.5,cpu調(diào)度線程的概率
//開啟線程
[thread1 start];

 /*
     第一個參數(shù):選擇器,調(diào)用哪個方法
     第二個參數(shù):目標對象
     第三個參數(shù):前面方法需要傳遞的參數(shù)
  */
 [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"參數(shù)"];

/*
 第三種創(chuàng)建線程的方式
 特點:默認開啟線程
 */
[self performSelectorInBackground:@selector(run:) withObject:@"后臺線程"];

pthread了解

//創(chuàng)建線程
pthread_t thread;
/*
 第一個參數(shù):線程對象
 第二個參數(shù):線程屬性
 第三個參數(shù):void *(*)(void *) 指向函數(shù)的指針
 第四個參數(shù):函數(shù)的參數(shù)
 */
pthread_create(&thread, NULL, run, NULL);

pthread_t thread1;
pthread_create(&thread1, NULL, run, NULL);

//void *(*)(void *)
void *run(void *param)
{
//    NSLog(@"---%@-",[NSThread currentThread]);
    for (NSInteger i =0 ; i<10000; i++) {
        NSLog(@"%zd--%@-",i,[NSThread currentThread]);
    }
    return NULL;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容