- NSThread
-(void)loadImageWithMultiThread{
//方法1:使用對(duì)象方法
//創(chuàng)建一個(gè)線程,第一個(gè)參數(shù)是請(qǐng)求的操作,第二個(gè)參數(shù)是操作方法的參數(shù)
// NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
// //啟動(dòng)一個(gè)線程,注意啟動(dòng)一個(gè)線程并非就一定立即執(zhí)行,而是處于就緒狀態(tài),當(dāng)系統(tǒng)調(diào)度時(shí)才真正執(zhí)行
// [thread start];
//方法2:使用類(lèi)方法
[NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];
}
- NSObject分類(lèi)擴(kuò)展方法
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg:在后臺(tái)執(zhí)行一個(gè)操作,本質(zhì)就是重新創(chuàng)建一個(gè)線程執(zhí)行當(dāng)前方法。
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait:在指定的線程上執(zhí)行一個(gè)方法,需要用戶(hù)創(chuàng)建一個(gè)線程對(duì)象。
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait:在主線程上執(zhí)行一個(gè)方法(前面已經(jīng)使用過(guò))。
- NSInvocationOperation
-(void)loadImageWithMultiThread{
/*創(chuàng)建一個(gè)調(diào)用操作
object:調(diào)用方法參數(shù)
*/
NSInvocationOperation *invocationOperation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
//創(chuàng)建完NSInvocationOperation對(duì)象并不會(huì)調(diào)用,它由一個(gè)start方法啟動(dòng)操作,但是注意如果直接調(diào)用start方法,則此操作會(huì)在主線程中調(diào)用,一般不會(huì)這么操作,而是添加到NSOperationQueue中
// [invocationOperation start];
//創(chuàng)建操作隊(duì)列
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
//注意添加到操作隊(duì)后,隊(duì)列會(huì)開(kāi)啟一個(gè)線程執(zhí)行此操作
[operationQueue addOperation:invocationOperation];
}
- NSBlockOperation
//更新UI界面,此處調(diào)用了主線程隊(duì)列的方法(mainQueue是UI主線程)
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self updateImageWithData:data andIndex:i];
}];
#pragma mark 多線程下載圖片
-(void)loadImageWithMultiThread{
int count=ROW_COUNT*COLUMN_COUNT;
//創(chuàng)建操作隊(duì)列
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
operationQueue.maxConcurrentOperationCount=5;//設(shè)置最大并發(fā)線程數(shù)
//創(chuàng)建多個(gè)線程用于填充圖片
for (int i=0; i<count; ++i) {
//方法1:創(chuàng)建操作塊添加到隊(duì)列
// //創(chuàng)建多線程操作
// NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
// [self loadImage:[NSNumber numberWithInt:i]];
// }];
// //創(chuàng)建操作隊(duì)列
//
// [operationQueue addOperation:blockOperation];
//方法2:直接使用操隊(duì)列添加操作
[operationQueue addOperationWithBlock:^{
[self loadImage:[NSNumber numberWithInt:i]];
}];
}
}
- NSOperation可以設(shè)置依賴(lài)線程
-(void)loadImageWithMultiThread{
int count=ROW_COUNT*COLUMN_COUNT;
//創(chuàng)建操作隊(duì)列
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
operationQueue.maxConcurrentOperationCount=5;//設(shè)置最大并發(fā)線程數(shù)
NSBlockOperation *lastBlockOperation=[NSBlockOperation blockOperationWithBlock:^{
[self loadImage:[NSNumber numberWithInt:(count-1)]];
}];
//創(chuàng)建多個(gè)線程用于填充圖片
for (int i=0; i<count-1; ++i) {
//方法1:創(chuàng)建操作塊添加到隊(duì)列
//創(chuàng)建多線程操作
NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
[self loadImage:[NSNumber numberWithInt:i]];
}];
//設(shè)置依賴(lài)操作為最后一張圖片加載操作
[blockOperation addDependency:lastBlockOperation];
[operationQueue addOperation:blockOperation];
}
//將最后一個(gè)圖片的加載操作加入線程隊(duì)列
[operationQueue addOperation:lastBlockOperation];
}
- GCD
異步執(zhí)行并發(fā)隊(duì)列不會(huì)調(diào)用主線程:
for (int i = 0; i < 10; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%d ---- %@",i, [NSThread currentThread]);
});
}
dispatch_semaphore_t: 每當(dāng)發(fā)送一個(gè)信號(hào)通知,則信號(hào)量+1;每當(dāng)發(fā)送一個(gè)等待信號(hào)時(shí)信號(hào)量-1,;如果信號(hào)量為0則信號(hào)會(huì)處于等待狀態(tài),直到信號(hào)量大于0開(kāi)始執(zhí)行。
/*初始化信號(hào)量
參數(shù)是信號(hào)量初始值
*/
_semaphore=dispatch_semaphore_create(1);
/*信號(hào)等待
第二個(gè)參數(shù):等待時(shí)間
*/
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
if (_imageNames.count>0) {
name=[_imageNames lastObject];
[_imageNames removeObject:name];
}
//信號(hào)通知
dispatch_semaphore_signal(_semaphore);
NSLock:
//初始化鎖對(duì)象
_lock=[[NSLock alloc]init];
//加鎖
[_lock lock];
if (_imageNames.count>0) {
name=[_imageNames lastObject];
[_imageNames removeObject:name];
}
//使用完解鎖
[_lock unlock];
@synchronized代碼塊: 如下代碼,self為同步對(duì)象,是以該對(duì)象是否為加鎖狀態(tài)來(lái)判斷該代碼塊是否應(yīng)該加鎖. 如果2個(gè)不同的實(shí)例對(duì)象,那么用self的話,就不會(huì)相互起作用,因?yàn)閟elf不是同一個(gè)了.
//線程同步
@synchronized(self){
if (_imageNames.count>0) {
name=[_imageNames lastObject];
[NSThread sleepForTimeInterval:0.001f];
[_imageNames removeObject:name];
}
}
NSCondition: NSCondition實(shí)現(xiàn)了NSLocking協(xié)議,所以它本身也有l(wèi)ock和unlock方法,因此也可以將它作為NSLock解決線程同步問(wèn)題,此時(shí)使用方法跟NSLock沒(méi)有區(qū)別,只要在線程開(kāi)始時(shí)加鎖,取得資源后釋放鎖即可,這部分內(nèi)容比較簡(jiǎn)單在此不再演示。當(dāng)然,單純解決線程同步問(wèn)題不是NSCondition設(shè)計(jì)的主要目的,NSCondition更重要的是解決線程之間的調(diào)度關(guān)系(當(dāng)然,這個(gè)過(guò)程中也必須先加鎖、解鎖)。NSCondition可以調(diào)用wati方法控制某個(gè)線程處于等待狀態(tài),直到其他線程調(diào)用signal(此方法喚醒一個(gè)線程,如果有多個(gè)線程在等待則任意喚醒一個(gè))或者broadcast(此方法會(huì)喚醒所有等待線程)方法喚醒該線程才能繼續(xù)。
//
// 線程控制
// MultiThread
//
// Created by Kenshin Cui on 14-3-22.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCMainViewController.h"
#import "KCImageData.h"
#define ROW_COUNT 5
#define COLUMN_COUNT 3
#define ROW_HEIGHT 100
#define ROW_WIDTH ROW_HEIGHT
#define CELL_SPACING 10
#define IMAGE_COUNT 9
@interface KCMainViewController (){
NSMutableArray *_imageViews;
NSCondition *_condition;
}
@end
@implementation KCMainViewController
#pragma mark - 事件
- (void)viewDidLoad {
[super viewDidLoad];
[self layoutUI];
}
#pragma mark - 內(nèi)部私有方法
#pragma mark 界面布局
-(void)layoutUI{
//創(chuàng)建多個(gè)圖片控件用于顯示圖片
_imageViews=[NSMutableArray array];
for (int r=0; r<ROW_COUNT; r++) {
for (int c=0; c<COLUMN_COUNT; c++) {
UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(c*ROW_WIDTH+(c*CELL_SPACING), r*ROW_HEIGHT+(r*CELL_SPACING ), ROW_WIDTH, ROW_HEIGHT)];
imageView.contentMode=UIViewContentModeScaleAspectFit;
[self.view addSubview:imageView];
[_imageViews addObject:imageView];
}
}
UIButton *btnLoad=[UIButton buttonWithType:UIButtonTypeRoundedRect];
btnLoad.frame=CGRectMake(50, 500, 100, 25);
[btnLoad setTitle:@"加載圖片" forState:UIControlStateNormal];
[btnLoad addTarget:self action:@selector(loadImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btnLoad];
UIButton *btnCreate=[UIButton buttonWithType:UIButtonTypeRoundedRect];
btnCreate.frame=CGRectMake(160, 500, 100, 25);
[btnCreate setTitle:@"創(chuàng)建圖片" forState:UIControlStateNormal];
[btnCreate addTarget:self action:@selector(createImageWithMultiThread) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btnCreate];
//創(chuàng)建圖片鏈接
_imageNames=[NSMutableArray array];
//初始化鎖對(duì)象
_condition=[[NSCondition alloc]init];
_currentIndex=0;
}
#pragma mark 創(chuàng)建圖片
-(void)createImageName{
[_condition lock];
//如果當(dāng)前已經(jīng)有圖片了則不再創(chuàng)建,線程處于等待狀態(tài)
if (_imageNames.count>0) {
NSLog(@"createImageName wait, current:%i",_currentIndex);
[_condition wait];
}else{
NSLog(@"createImageName work, current:%i",_currentIndex);
//生產(chǎn)者,每次生產(chǎn)1張圖片
[_imageNames addObject:[NSString stringWithFormat:@"http://images.cnblogs.com/cnblogs_com/kenshincui/613474/o_%i.jpg",_currentIndex++]];
//創(chuàng)建完圖片則發(fā)出信號(hào)喚醒其他等待線程
[_condition signal];
}
[_condition unlock];
}
#pragma mark 加載圖片并將圖片顯示到界面
-(void)loadAnUpdateImageWithIndex:(int )index{
//請(qǐng)求數(shù)據(jù)
NSData *data= [self requestData:index];
//更新UI界面,此處調(diào)用了GCD主線程隊(duì)列的方法
dispatch_queue_t mainQueue= dispatch_get_main_queue();
dispatch_sync(mainQueue, ^{
UIImage *image=[UIImage imageWithData:data];
UIImageView *imageView= _imageViews[index];
imageView.image=image;
});
}
#pragma mark 請(qǐng)求圖片數(shù)據(jù)
-(NSData *)requestData:(int )index{
NSData *data;
NSString *name;
name=[_imageNames lastObject];
[_imageNames removeObject:name];
if(name){
NSURL *url=[NSURL URLWithString:name];
data=[NSData dataWithContentsOfURL:url];
}
return data;
}
#pragma mark 加載圖片
-(void)loadImage:(NSNumber *)index{
int i=(int)[index integerValue];
//加鎖
[_condition lock];
//如果當(dāng)前有圖片資源則加載,否則等待
if (_imageNames.count>0) {
NSLog(@"loadImage work,index is %i",i);
[self loadAnUpdateImageWithIndex:i];
[_condition broadcast];
}else{
NSLog(@"loadImage wait,index is %i",i);
NSLog(@"%@",[NSThread currentThread]);
//線程等待
[_condition wait];
NSLog(@"loadImage resore,index is %i",i);
//一旦創(chuàng)建完圖片立即加載
[self loadAnUpdateImageWithIndex:i];
}
//解鎖
[_condition unlock];
}
#pragma mark - UI調(diào)用方法
#pragma mark 異步創(chuàng)建一張圖片鏈接
-(void)createImageWithMultiThread{
dispatch_queue_t globalQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//創(chuàng)建圖片鏈接
dispatch_async(globalQueue, ^{
[self createImageName];
});
}
#pragma mark 多線程下載圖片
-(void)loadImageWithMultiThread{
int count=ROW_COUNT*COLUMN_COUNT;
dispatch_queue_t globalQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i=0; i<count; ++i) {
//加載圖片
dispatch_async(globalQueue, ^{
[self loadImage:[NSNumber numberWithInt:i]];
});
}
}
@end
在上面的代碼中l(wèi)oadImage:方法是消費(fèi)者,當(dāng)在界面中點(diǎn)擊“加載圖片”后就創(chuàng)建了15個(gè)消費(fèi)者線程。在這個(gè)過(guò)程中每個(gè)線程進(jìn)入圖片加載方法之后都會(huì)先加鎖,加鎖之后其他進(jìn)程是無(wú)法進(jìn)入“加鎖代碼”的。但是第一個(gè)線程進(jìn)入“加鎖代碼”后去加載圖片卻發(fā)現(xiàn)當(dāng)前并沒(méi)有任何圖片,因此它只能等待。一旦調(diào)用了NSCondition的wait方法后其他線程就可以繼續(xù)進(jìn)入“加鎖代碼”(注意,這一點(diǎn)和前面說(shuō)的NSLock、@synchronized等是不同的,使用NSLock、@synchronized等進(jìn)行加鎖后無(wú)論什么情況下,只要沒(méi)有解鎖其他線程就無(wú)法進(jìn)入“加鎖代碼”),同時(shí)第一個(gè)線程處于等待隊(duì)列中(此時(shí)并未解鎖)。第二個(gè)線程進(jìn)來(lái)之后同第一線程一樣,發(fā)現(xiàn)沒(méi)有圖片就進(jìn)入等待狀態(tài),然后第三個(gè)線程進(jìn)入。。。如此反復(fù),直到第十五個(gè)線程也處于等待。此時(shí)點(diǎn)擊“創(chuàng)建圖片”后會(huì)執(zhí)行createImageName方法,這是一個(gè)生產(chǎn)者,它會(huì)創(chuàng)建一個(gè)圖片鏈接放到imageNames中,然后通過(guò)調(diào)用NSCondition的signal方法就會(huì)在條件等待隊(duì)列中選擇一個(gè)線程(該線程會(huì)任意選取,假設(shè)為線程A)開(kāi)啟,那么此時(shí)這個(gè)線程就會(huì)繼續(xù)執(zhí)行。在上面代碼中,wati方法之后會(huì)繼續(xù)執(zhí)行圖片加載方法,那么此時(shí)線程A啟動(dòng)之后繼續(xù)執(zhí)行圖片加載方法,當(dāng)然此時(shí)可以成功加載圖片。加載完圖片之后線程A就會(huì)釋放鎖,整個(gè)線程任務(wù)完成。此時(shí)再次點(diǎn)擊”創(chuàng)建圖片“按鈕重復(fù)前面的步驟加載其他圖片。
詳情:http://www.cnblogs.com/kenshincui/p/3983982.html