iOS多線程總結

一 多線程之間的關係

二、
安全

二 NSThread

一旦線程中止死亡了,就不能再啓動。因此線程NSThread不能爲全局變量多線程

1>.建立和啓動

1.第一種方法:直接建立,手動啓動
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:@"www.baidu.com"];
    [thread start];

2.第二種方法:建立後當即啓動    
    [NSThread detachNewThreadSelector:@selector(download) toTarget:self withObject:@"www.baidu.com"];
    
3.第三種方法:隱式建立
    //主線程
    [self performSelector:@selector(download:) withObject:@"www.baidu.com"];
    //子線程
    [self performSelectorInBackground:@selector(download:) withObject:@"www.baidu.com"];
    
object是selector方法傳遞的參數
-(void)download:(NSString *)url
{
    NSLog(@"download-- %@  %@",url,[NSThread currentThread]);
}

2>.睡眠的用法

延遲執行不要勇sleep,壞處:卡住主線程
1.第一種
    [NSThread sleepForTimeInterval:5.0];
2.第二種    
    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3.0];
    [NSThread sleepUntilDate:date];

3>.強制中止進程

+(void)exit

4>.其餘用法

+(NSThread *)mainThread;
+(NSThread *)currentThread
-(BOOL)isMainThread;
+(BOOL)isMainThread;

5>.線程間通訊

在1個進程中,線程每每不是孤立存在的,多個線程之間須要常常進行通訊。體如今兩個方面:一,1個線程的數據傳遞給另外一個線程。二,在1個線程中執行完特定任務後,轉到另外一個線程繼續執行任務
併發

-(void)download:(NSString *)url
{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
    UIImage *image = [UIImage imageWithData:data];
    
    [self performSelectorOnMainThread:@selector(pic:) withObject:image waitUntilDone:YES];
}

-(void)pic:(UIImage *)image
{
    NSLog(@"pic:%@",image);
    self.imageView.image = image;
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(download:) withObject:@"http://g.hiphotos.baidu.com/image/h%3D200/sign=f23ec3ed1fd8bc3ed90801cab289a6c8/7a899e510fb30f24dc189ad4ce95d143ac4b0362.jpg"];
}


三 GCD

1>線程:同步與異步

同步:只能在當前線程中執行任務,不具有開啓新線程的能力異步

異步:能夠在新的線程中執行任務,具有開啓新線程的能力async

2>任務:併發與串行

併發:可讓多個任務併發(同時)執行,自動開啓多線程。只有在異步下才有效atom

串行:讓任務一個接一個地執行url

-(void)asyncGlobalQueue
{
    //得到全局的併發隊列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //第一個參數是優先級
    //異步並行。自動建立多條線程
    dispatch_async(queue, ^{
        NSLog(@"將任務放到全局隊列中執行 %@",  [NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"異步並行1 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"異步並行2 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"異步並行3 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"異步並行4 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"異步並行5 %@",  [NSThread currentThread]);
        });
        
    });
}

-(void)asyncSerialQueue
{
    //異步串行,自動會建立線程,但只開1條
    dispatch_queue_t queue = dispatch_queue_create("cn.wx", NULL);

    dispatch_async(queue, ^{
        NSLog(@"異步串行1 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"異步串行2 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"異步串行3 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"異步串行4 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"異步串行5 %@",  [NSThread currentThread]);
    });
}

-(void)syncGlobalQueue
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //同步並行。不會建立線程,使用主線程
    dispatch_sync(queue, ^{
        NSLog(@"同步並行1 %@",  [NSThread currentThread]);
        NSLog(@"同步並行2 %@",  [NSThread currentThread]);
        NSLog(@"同步並行3 %@",  [NSThread currentThread]);
        NSLog(@"同步並行4 %@",  [NSThread currentThread]);
        NSLog(@"同步並行5 %@",  [NSThread currentThread]);
    });
}

-(void)syncSerialQueue
{
    dispatch_queue_t queue = dispatch_queue_create("cn.wx", NULL);
    //同步串行。不會建立線程,使用主線程
    dispatch_sync(queue, ^{
        NSLog(@"同步並行1 %@",  [NSThread currentThread]);
        NSLog(@"同步並行2 %@",  [NSThread currentThread]);
        NSLog(@"同步並行3 %@",  [NSThread currentThread]);
        NSLog(@"同步並行4 %@",  [NSThread currentThread]);
        NSLog(@"同步並行5 %@",  [NSThread currentThread]);
    });
}

3>.主隊列

-(void)mainQueue
{
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        NSLog(@"雖然是異步,可是是在主線程執行,因此不會開線程");
    });
//    dispatch_sync(queue, ^{
//        NSLog(@"不能在串行上使用主隊列,不然會阻塞");
//    });
    
}

4>.線程間通訊

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"子線程進行操做");
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"回主線程加載圖片");
        });
        
    });

5>.延時執行

不要使用sleep,會卡住主線程spa

第一種:
[self performSelector:@selector(down) withObject:@"abv" afterDelay:3];
第二種:
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"xx");//回到主線程
    });
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"xx");//回到子線程
    });

6>.只執行一次

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"xx");
    })


四 NSOperation

1>.簡述

先將須要執行的操做封裝到一個NSOperation對象,一個對象就至關於GCD的一個block線程

而後將NSOperation對象添加到NSOperationQueue中code

系統會自動將NSOperationQueue中的NSOperation取出來

將取出的NSOperation封裝的操做放到一條線程中執行

2>.NSOperation的使用

NSOperation是個抽象類,不具有封裝的能力,必須使用它的子類

1>NSInvocationOperation

    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
    /*
    [operation start]; 若是直接start,那麼將會在當前線程(主線程)同步執行
    */
     //添加操做到隊列中
    [queue addOperation:operation];

2>NSBlockOperation

第一種狀況:同步
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載一 %@",[NSThread currentThread]);
    }];
    [operation start]; // 若是直接start,那麼將會在當前線程(主線程)同步執行
    
第二種狀況:異步
    NSBlockOperation *operation = [[NSBlockOperation alloc] init];
    //operation操做添加多個操做
    [operation addExecutionBlock:^{
        NSLog(@"下載一 %@",[NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^{
        NSLog(@"下載二 %@",[NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^{
        NSLog(@"下載三 %@",[NSThread currentThread]);
    }];
    
    [operation start];

ps:NSBlockOperation還能夠直接建立使用對象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載一 %@",[NSThread currentThread]);
    }];

3>自定義子類繼承NSOperation

3.NSOperationQueue的使用

1>.基本使用

    //1.建立一個隊列(非主隊列)
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //設置最大併發數
    queue.maxConcurrentOperationCount = 2;
    
    //2.建立操做
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載圖片1 -- %@",[NSThread currentThread]);
    }];
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載圖片2 -- %@",[NSThread currentThread]);
    }];
    NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(down) object:nil];
    
    //操做完後立刻執行另外一個操做
    [operation1 setCompletionBlock:^{
        NSLog(@"下載圖片222");
    }];
    
    //操做依賴,注意不能相互依賴
    [operation2 addDependency:operation1];
    [operation3 addDependency:operation2];
    
    //3.添加操做到隊列中(自動異步執行任務,併發)
    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];

2>其餘用法

    [queue cancelAllOperations]; //取消隊列的全部操做。也能夠直接調用NSOperation的cancel
    [queue setSuspended:YES]; //暫停和恢復隊列。yes爲暫停
    
經常使用場景:
-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    [queue cancelAllOperations];
}

-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
    [queue setSuspended:YES];
}

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    [queue setSuspended:NO];
}

3>.線程安全

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        //1.異步下載圖片
        NSURL *url = [NSURL URLWithString:@"www.baidu.com"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        //2.回到主線程設置圖片
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
        }];
    }];


五 互斥鎖

    self.obj = [[NSObject alloc] init];
    //鎖任意對象,而且須要是惟一一把,因此須要創建個全局變量對象
    @synchronized(self.obj) {
        
    }

2.atomic:線程安全,須要消耗大量的資源。不建議須要


六 線程注意點

1.不要同時開太多線材(1~3條線材便可,不要超過5條)

2.線程概念

1>主線程:UI線程,顯示、刷新UI界面,處理UI控件的事件

2>子線程:後臺線程,異步線程

3.不要把耗時的操做放在主線程,要放在子線程中執行

相關文章
相關標籤/搜索