NSRunLoop 循环机制

NSRunTime 循环时刻


什么时候创建子线程是有条件的

1.进行大量数据运算   for

数据库查询 select 将 select放在子线程中

2.网络请求 异步(将异步放在子线程中)


IOS中关于UI的添加必须在主线程中操作

子线程不能修改,创建跟UI相关的任何内容

想要修改,必须在主线程上

iOS开发异步并发多线程 ios开发多线程的使用_GCD

进程号 : 线程号


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSString *str = @"点击测试";
    NSString *str1 = @"等运算结果吧,别急";
    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 75, 40)];
    button.backgroundColor = [UIColor cyanColor];
    [button setTitle:str forState:UIControlStateNormal];
    [button setTitle:str1 forState:UIControlStateHighlighted];
    [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    [button release];
}
- (void)buttonAction:(id)sender
{
    unsigned long result = 0;
    for (int i = 1; i < 635500000; i++) {
        result = result+i;
        NSLog(@"%lu", result);
    }
}




NSThread 轻量级的多线程

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSString *str = @"点击测试";
    NSString *str1 = @"等运算结果吧,别急";
    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 75, 40)];
    button.backgroundColor = [UIColor cyanColor];
    [button setTitle:str forState:UIControlStateNormal];
    [button setTitle:str1 forState:UIControlStateHighlighted];
    [button addTarget:self action:@selector(createThread:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    [button release];
}

//NSThread方法创建子线程   这个只是告诉哪个方法在子线程中跑
- (void)createThread:(id)sender
{
    //NSThread第一种写法
//    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction) object:NULL];
//    [thread start];
//    [thread release];
    
    //NSThread第二种写法
    [NSThread detachNewThreadSelector:@selector(threadAction) toTarget:self withObject:NULL];
}

- (void)threadAction
{
    //创建autoreleasepool方法一
//    @autoreleasepool {
//        unsigned long result = 0;
//        for (int i = 1; i < 635500000; i++) {
//            result = result+i;
//            NSLog(@"%lu", result);
//        }
//    }

    //创建autoreleasepool  方法二   只能在MRC中 使用
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //unsigned 无符号的意思   unsigned long 无符号长整形
    unsigned long result = 0;
    for (int i = 1; i < 635500000; i++) {
        result = result+i;
        NSLog(@"%lu", result);
    }
    [pool release];   //NSAutoreleasePool  释放池的第一种方法
//    [pool drain]      //NSAutoreleasePool  释放池的第二种方法
}




NSOperation


NSOperationQueue 称为线程队列

OperationQueue才是多线程

#pragma mark -
#pragma mark Operation创建子线程
#import "Operation.h"
.
.
.
.
.
.
- (void)createOperation
{
    NSLog(@"%s",__func__);
    Operation *operation = [[Operation alloc] init];
    Operation *operation1 = [[Operation alloc] init];
    Operation *operation2 = [[Operation alloc] init];
    Operation *operation3 = [[Operation alloc] init];
    Operation *operation4 = [[Operation alloc] init];
    
    operation.delegate = self;
    //    [operation start];
    
    //下面这两行  等于start的功能     主要是看进程号,看进程号跟主线程的进程号是不是一样  来确定是否在主线程上
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue setMaxConcurrentOperationCount:2];//限制子线程的最大并行数
    [queue addOperation:operation];
    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];
    [queue addOperation:operation4];
    [queue release];
    
    
    //Operation 要和 OperationQueue  成对使用  单独使用没有用
    //OperationQueue才是多线程  operation只是多线程中的一个方法
}

- (void)sendImage:(UIImage *)image
{
    UIImageView *aImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, self.view.frame.size.height)];
    aImage.image = image;
    [self.view addSubview:aImage];
    [aImage release];
}


#import <Foundation/Foundation.h>
@protocol OperationDelegate;



@interface Operation : NSOperation

@property(nonatomic , assign) id<OperationDelegate>delegate;

@end


@protocol OperationDelegate <NSObject>

- (void)sendImage:(UIImage *)image;

@end





#import <Foundation/Foundation.h>
@protocol OperationDelegate;



@interface Operation : NSOperation

@property(nonatomic , assign) id<OperationDelegate>delegate;

@end


@protocol OperationDelegate <NSObject>

- (void)sendImage:(UIImage *)image;

@end




#import "Operation.h"

@implementation Operation

- (void)dealloc
{
    [super dealloc];
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        
    }
    return self;
}

- (void)main
{
//    @autoreleasepool {
//        NSLog(@"%@",[NSThread currentThread]);
//        unsigned long result = 0;
//        for (int i = 1; i < 10; i++) {
//            result = result+i;
//            NSLog(@"%lu", result);
//        }
//    }
    
    NSURL * url = [NSURL URLWithString:@" 图片网址(自己写,博客上不让发链接) "];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *aImage = [UIImage imageWithData:data];
    
    //判断代理人是否能够调用这个方法
    if ([self.delegate respondsToSelector:@selector(sendImage:)]) {
//        [self.delegate sendImage:aImage];
        [self performSelectorOnMainThread:@selector(finished:) withObject:aImage waitUntilDone:YES];
    }
}
- (void)finished:(UIImage *)aimage
{
    [self.delegate sendImage:aimage];
}


@end



NSObject 创建子线程

#pragma mark -
#pragma mark NSObject创建子线程
- (void)objectThread
{
    [self performSelectorInBackground:@selector(threadAction) withObject:NULL];
}



NSthread

NSOperation

NSObject

以上三个是IOS4.0以前经常用的 

他们返回主线程的方法就是用

[performSelectorInBackground: withObject: ]


________________________________________________________________________________________________________________________________



GCD(Grand Central Dispatch)

Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化应用程序支持多核心处理器和其他的对称多处理系统的系统。其建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。

GCD工作原理

1. GCD让程序平行排队执行任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。

2. 一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

3. GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行



dispatch queue分为下面三种:

Serial:      

又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。

Concurrent:

又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。

Main dispatch queue:

它是全局可用的serial queue,它是在应用程序主线程上执行任务的。



#import "MainViewController.h"

@interface MainViewController ()

@end

@implementation MainViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

#pragma mark - 
#pragma mark 创建一个同步的线程队列

- (void)createSerailGCD
{
    //@""  是NSString类型   " " 是char类型
    //创建一个变量名为queue的线程队列,队列的名字叫"first",队列类型为 同步的.
    dispatch_queue_t queue = dispatch_queue_create("first", DISPATCH_QUEUE_SERIAL);
    //异步执行线程队列
    dispatch_async(queue, ^{
        //在多线程中执行的代码
        NSURL * url = [NSURL URLWithString:@" <span style="font-family: Arial, Helvetica, sans-serif;">图片地址 </span><span style="font-family: Arial, Helvetica, sans-serif;">"];</span>
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *aImage = [UIImage imageWithData:data];
        //异步返回主线程     dispatch_get_main_queue() 返回主线程的方法
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImageView * imageView = [[UIImageView alloc] initWithImage:aImage];
            [imageView release];
        });
    });
}
#pragma mark -
#pragma mark 创建一个并发的线程队列
- (void)createConcurrentGCD
{
    //并发中,下面注释这段可以省略 用别的代替   上面跟下面的效果是一样的
//    dispatch_queue_t queue = dispatch_queue_create("second", DISPATCH_QUEUE_CONCURRENT);
//    dispatch_async(queue, ^{
//        
//    });
    //由这句话代表上面注释这段话  DISPATCH_QUEUE_PRIORITY_DEFAULT 默认的 级别高的先运行,级别低的后运行
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //在多线程中执行的代码
        NSURL * url = [NSURL URLWithString:@" 图片地址 "];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *aImage = [UIImage imageWithData:data];
        //异步返回主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImageView * imageView = [[UIImageView alloc] initWithImage:aImage];
            [imageView release];
        });
    });
}
@end<span style="font-size:24px;">
</span>

返回主线程方法

返回主线程类型

方法:

GCD

dispatch_get_main_queue()

NSObject

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait


线程互斥场景

线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。因此需要加上互斥锁来进行顺序访问,最具有代表性的就是买票系统!



条件锁


NSConditionLock称为条件锁,它的应用场景通常为线程同步。

当我们在使用多线程的时候,有时一把只会lock和unlock的锁未必就能完全满足我们的使用。因为普通的锁只能关心锁与不锁,而不在乎用什么钥匙才能开锁,而我们在处理资源共享的时候,多数情况是只有满足一定条件的情况下才能打开这把锁,比如生产者和消费者!

递归锁


NSRecursiveLock称为递归锁

平时我们在代码中使用锁的时候,最容易犯的一个错误就是造成死锁,而容易造成死锁的一种情形就是在递归或循环中。

NSRecursiveLock


在线程1中的递归block中,锁会被多次的lock,所以自己也被阻塞了,那么如何在递归或循环中正确的使用锁呢?此处的“锁”如果换用NSRecursiveLock对象,问题便得到解决了,NSRecursiveLock类定义的锁可以在同一线程多次lock,而不会造成死锁。递归锁会跟踪它被多少次lock。每次成功的lock都必须平衡调用unlock操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得