多线程

来源:互联网 发布:程序员面试题库 编辑:程序博客网 时间:2024/05/27 00:54

一个运行的程序就是一个进程或者叫做一个任务

一个进程至少包含一个线程,线程是程序的执行流

iOS 程序启动时,在创建一个进程的同事,会开始运行一个程序,该程序被称作主线程

主线程是其他线程最终的父线程,所有界面的显示操作必须在主线程进行!!!!

后台线程无法更新UI界面和响应用户点击事件

系统中的每一个进程都是有自己独立的虚拟内存空间,而同一个进程中的多个线程则公用进程的内存空间

每创建一个新的线程,都会消耗一定内存的CPU时间

当多线程对同一个资源出现争夺的时候需要注意线程安全问题

线程的使用不是无节制的 :iOS 主线程的堆栈大小是1M,从第二个线程开始就是512KB,这些数值不能通过编译器开关和线程API函数更改 

只有主线程有直接修改UI的能力

 


一、NSObject多线程方法

1、[NSThread currentThread]; 可以返回当前运行的线程

      num = 1 说明是主线程

      在任务多线程技术中,均可以使用此方法查看当前的线程情况。

2、新建后台线程,调度任务

     [selfperformSelectorInBackground:@selector(bgTask)withObject:nil];

     使用performSelectorInBackground是可以修改UI的,不是强烈不建议这样使用。

3、更新界面

     使用performSelectorOnMainThread可以在主线程上执行任务。

     提示:NSObject对象均可以调用此方法。

4、内存管理

     线程任务要包在@autoreleasepool(自动释放池)中,否则容易引起内存泄露,而且非常难发现。

5、总结:使用简单,量级轻,不能控制线程的执行顺序

例如:

@implementation ViewController


- (void)viewDidLoad {

    [superviewDidLoad];

    UIButton *button1 =[UIButtonbuttonWithType:UIButtonTypeCustom];

    button1.backgroundColor =[UIColorredColor];

    button1.frame =CGRectMake(50,50, 100,50);

    [button1 setTitle:@"耗时操作"forState:UIControlStateNormal];

    [button1 addTarget:selfaction:@selector(buttton1)forControlEvents:UIControlEventTouchUpInside];

    [self.viewaddSubview:button1];

    UIButton *button2 =[UIButtonbuttonWithType:UIButtonTypeCustom];

    button2.backgroundColor =[UIColorredColor];

    button2.frame =CGRectMake(50,150, 100,50);

    [button2 setTitle:@"普通操作"forState:UIControlStateNormal];

    [button2 addTarget:selfaction:@selector(button2)forControlEvents:UIControlEventTouchUpInside];

    [self.viewaddSubview:button2];

}

-(void)buttton1

{

    //后台耗时操作

    //performSelectorInBackground会创建一个后台线程,并在该线程中执行调用的方法

//    performSelectorInBackground是可以修改UI的但是强烈不建议使用

    [selfperformSelectorInBackground:@selector(bgTask)withObject:nil];

}

-(void)button2

{

}

-(void)bgTask

{

    @autoreleasepool {

        for (int i =0; i  < 30000000; i++) {

            NSLog(@"%d",i);

        }


        //在主线程中修改所需要的操作或界面内容;withObject:所需要传递的参数

        [selfperformSelectorOnMainThread:@selector(change)withObject:nilwaitUntilDone:YES];

    }

}

-(void)change

{

}

二、NThread

 1、类方法

detachNewThreadSelector直接启动线程,调用选择器方法

2、成员方法

initWithTarget需要使用start方法才能启动实例化出来的线程

优点:简单

缺点:控制线程的生命周期比较困难

           控制并发线程数

           先后顺序困难

例如:

#import "ViewController.h"


@interface ViewController ()

@property(nonatomic,strong)NSSet *imageViewSet;

@end


@implementation ViewController

-(void)setUpUI{

    //实例化图像视图集合

    NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];

    NSInteger w =self.view.frame.size.width/8;

    NSInteger h =self.view.frame.size.height/8;

    for (int row =0; row < 7; row++) {

        for (int col =0; col < 4; col++) {

            //计算图片的位置

            NSInteger x = col * w;

            NSInteger y = row * h;

            UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];

            //顺序填充图片

            NSInteger num = (row *4 * col) % 17 +1;

            NSString *imageName =[NSStringstringWithFormat:@"图片名称%ld",num];

            UIImage *image = [UIImageimageNamed:imageName];

            [imageview setImage:image];

            [self.viewaddSubview:imageview];

            [imageSet addObject:imageview];

            

        }

    }

    self.imageViewSet = imageSet;

    //添加按钮

    UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];

    [button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];

    [button setTitle:@"刷新图片"forState:UIControlStateNormal];

    [button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];

    [self.viewaddSubview:button];

    

}

-(void)click

{

    [selfthreadLoad];

}


#pragma mark - NSThread方法

-(void)threadLoadImage:(UIImageView *)imageView{

    @autoreleasepool {

        NSInteger num =arc4random_uniform(17) +1;

        NSString *imageName = [NSStringstringWithFormat:@"图片名称%ld",num];

        UIImage *image =[UIImageimageNamed:imageName];

        //主线程更新UI

        [imageView performSelectorOnMainThread:@selector(setImage:)withObject:image waitUntilDone:YES];

      

    }

   

}

-(void)threadLoad

{

    for (UIImageView *imagevin self.imageViewSet) {

        //新建线程调用threadLoadImage方法

//        [NSThread detachNewThreadSelector:@selector(threadLoadImage:) toTarget:self withObject:imagev];

        NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(threadLoadImage:)object:imagev];

        //启动线程

        [thread start];

    }

}




- (void)viewDidLoad {

    [superviewDidLoad];

    

    [selfsetUpUI];

    

}

三、NSOperation

1、NSOperation的两个子类NSInvocationOperation,NSBlockOperation


例如:

#import "ViewController.h"


@interface ViewController ()

@property(nonatomic,strong)NSSet *imageViewSet;

@property(strong,nonatomic)NSOperationQueue *queue;

@end


@implementation ViewController

-(void)setUpUI{

    //实例化图像视图集合

    NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];

    NSInteger w =self.view.frame.size.width/8;

    NSInteger h =self.view.frame.size.height/8;

    for (int row =0; row < 7; row++) {

        for (int col =0; col < 4; col++) {

            //计算图片的位置

            NSInteger x = col * w;

            NSInteger y = row * h;

            UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];

            //顺序填充图片

            NSInteger num = (row *4 * col) % 17 +1;

            NSString *imageName =[NSStringstringWithFormat:@"图片名称%ld",num];

            UIImage *image = [UIImageimageNamed:imageName];

            [imageview setImage:image];

            [self.viewaddSubview:imageview];

            [imageSet addObject:imageview];

            

        }

    }

    self.imageViewSet = imageSet;

    //添加按钮

    UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];

    [button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];

    [button setTitle:@"刷新图片"forState:UIControlStateNormal];

    [button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];

    [self.viewaddSubview:button];

    

    

}

-(void)click

{

   // [selfoperationLoad];

    [selfoperationBlockLoad];

}


#pragma mark - NSOperation方法


-(void)operationBlockLoad

{

    for (UIImageView *imagevin self.imageViewSet) {

    NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{

        [selfoperationLoadImage:imagev];

    }];

        [self.queueaddOperation:op];

    }

}


-(void)operationLoadImage:(UIImageView *)imageView{

    @autoreleasepool {

        NSInteger num =arc4random_uniform(17) +1;

        NSString *imageName = [NSStringstringWithFormat:@"图片名称%ld",num];

        UIImage *image =[UIImageimageNamed:imageName];

        //主线程更新UI

      [[NSOperationQueuemainQueue]addOperationWithBlock:^{

          [imageView setImage:image];

      }];

      

    }

   

}

-(void)operationLoad

{

    //队列可以设置同时并发线程的数量

    [self.queuesetMaxConcurrentOperationCount:3];

    for (UIImageView *imagevin self.imageViewSet) {

        NSInvocationOperation *op =[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(operationLoadImage:)object:imagev];

        //如果直接调用start,实在主线程队列上运行的,不会开启新的线程

        [op start];

        //Invocation添加到队列,一添加到队列,就会开启新的线程执行任务

        [self.queueaddOperation:op];

    }

}

#pragma mark - NSOperation操作之间的顺序

-(void)operationDemo

{

    NSBlockOperation *op1 = [NSBlockOperationblockOperationWithBlock:^{

        

    }];

    NSBlockOperation *op2 = [NSBlockOperationblockOperationWithBlock:^{

        

    }];

    NSBlockOperation *op3 = [NSBlockOperationblockOperationWithBlock:^{

        

    }];


    //Dependency依赖依赖关系可以多重依赖

    [op2 addDependency:op1];

    [op3 addDependency:op2];

    [self.queueaddOperation:op3];

    [self.queueaddOperation:op1];

    [self.queueaddOperation:op2];

}


- (void)viewDidLoad {

    [superviewDidLoad];

    

    [selfsetUpUI];

    //实例化操作队列

    self.queue = [[NSOperationQueuealloc]init];

    

}

四、GCD

#import "ViewController.h"


@interface ViewController ()

@property(nonatomic,strong)NSSet *imageViewSet;


@end


@implementation ViewController

-(void)setUpUI{

    //实例化图像视图集合

    NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];

    NSInteger w =self.view.frame.size.width/8;

    NSInteger h =self.view.frame.size.height/8;

    for (int row =0; row < 7; row++) {

        for (int col =0; col < 4; col++) {

            //计算图片的位置

            NSInteger x = col * w;

            NSInteger y = row * h;

            UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];

            //顺序填充图片

            NSInteger num = (row *4 * col) % 17 +1;

            NSString *imageName =[NSStringstringWithFormat:@"图片名称%ld",num];

            UIImage *image = [UIImageimageNamed:imageName];

            [imageview setImage:image];

            [self.viewaddSubview:imageview];

            [imageSet addObject:imageview];

            

        }

    }

    self.imageViewSet = imageSet;

    //添加按钮

    UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];

    [button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];

    [button setTitle:@"刷新图片"forState:UIControlStateNormal];

    [button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];

    [self.viewaddSubview:button];

    

    

}

-(void)click

{

    [selfgcdLoad];

    

}





#pragma mark - GCD加载图像

-(void)gcdLoad

{

    //派发dispatch异步async执行,并发执行

    //PRIORITY优先级,一般选择默认的即可

    //获取全局队列

    dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

           for (UIImageView *imagevin self.imageViewSet) {

               dispatch_async(queue, ^{

                   NSInteger num =arc4random_uniform(17) +1;

                   NSString *imageName = [NSStringstringWithFormat:@"图片名称%ld",num];

                   UIImage *image =[UIImageimageNamed:imageName];

                   //设置图像,在主线程队列设置UI

                   dispatch_async(dispatch_get_main_queue(), ^{

                       [imagev setImage:image];

                   });

               });

        }

  

}

#pragma mark - GCD

-(void)gcdDemo

{

    //全局队列中调用异步任务开发时候不用考虑并发线程数量问题

//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//    dispatch_async(queue, ^{

//        

//    });

    //    dispatch_async(queue, ^{

    //

    //    });

    //    dispatch_async(queue, ^{

    //

    //    });

    //串行队列,需要创建,不能够get

    dispatch_queue_t queue =dispatch_queue_create("myQUeue",DISPATCH_QUEUE_SERIAL);

       dispatch_async(queue, ^{

    

        });

       dispatch_async(queue, ^{

        

       });

       dispatch_async(queue, ^{

        

       });

    

}

- (void)viewDidLoad {

    [superviewDidLoad];

    

    [selfsetUpUI];


    

}





@end




0 0
原创粉丝点击