iOS -- 线程 还有待补全--(关于线程死锁,解决办法等。。)(NSThread、NSOperation、GCD) -- ASI/AFNetWork

提到线程,就不得不说什么是进程。进程是:一个程序一个数据集合上一次运行。这句话也就是说,一个进程,是一个程序在CPU中运行的体现。线程是进程的具体实现,也就是说,一个进程在CPU中进行时间片轮转,真正轮转执行的时一个进程的线程。

进程是系统进行资源分配和调度的一个独立单位。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

线程是处理器调度的基本单位


 

        开启多线程,在iOS中有三种方法开启多线程

     

        1NSThread            最接近底层   但是这种线程是不安全的

(因为线程可抢夺,当一个线程先访问了外部变量,在对其进行操作,过了一会,另一个优先级别更高的线程开启了,它也需要使用到同一个外部变量,对它操作完后,这是第一次使用这个外部变量的线程再次使用这个外部变量,就会发生预想不到的错误)。解决办法,就是加锁。线程中还容易发生死锁,这个问题,编者以后补上。

        2NSOperation       更好用,线程安全

        3GCD                   NSOperation一样,更好用,线程安全



第一种  NSThread

           

   开辟线程 有对象方法和类方法

                          a :对象方法 创建子线程:

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

   //线程名字

   thread.name=@"休眠1s";

   //线程优先级

   thread.threadPriority=0.5;

   [threadstart];


b :类方法 创建子线程

[NSThreaddetachNewThreadSelector:@selector(doThing1)toTarget:selfwithObject:nil];

使用NSThread创建的子线程,返回子线程的方法:

//返回主线程中执行执行  ---  func

    [selfperformSelectorOnMainThread:@selector(func)withObject:nilwaitUntilDone:NO];


第二种 NSOperation

步骤:01:创建一个操作队列。

  //创建操作队列

    NSOperationQueue *quene=[[NSOperationQueuealloc]init];

    

   //设置队列的最大操作数--(并行执行 )

   quene.maxConcurrentOperationCount=10;

02 :创建操作,将其加入到操作队列中。

创建操作,又有三种方法:
a: NSInvocationOperation

//第一种  NSInvocationOperation

   NSInvocationOperation *operation=[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(doThing1)object:nil];

    

   //将操作加入到队列中

    [queneaddOperation:operation];


b: NSBlockOperation

//第二种  NSBlockOperation

    NSBlockOperation *blockOperation=[NSBlockOperationblockOperationWithBlock:^{

       [selfthird];

   }];

   [queneaddOperation:blockOperation];


c: 自定义一个操作,继续自 NSOperation

//第三中自定义操作

   /**

               自定义操作,由于是继承自NSOperation,所以我们可以在自定义操作中,设置成员变量,或属性,方法。这样的话,逻辑更 加清晰。

        */

   AZMyOperation *myOperation=[[AZMyOperationalloc]init];

    [queneaddOperation:myOperation];



// [NSOperationQueue mainQueue];主线程




附:AZMyOperation

<span style="font-size:14px;">#import <Foundation/Foundation.h>

@interface AZMyOperation : NSOperation

@end</span>

<span style="font-size:14px;">#import "AZMyOperation.h"

@implementation AZMyOperation

//操作的入口函数
-(void)main
{
    NSLog(@"自定义操作");
    
}

@end</span>

附:   NSThread 和  NSOperation 的小demo
<span style="font-size:14px;">#import "AZViewController.h"
#import "AZMyOperation.h"
@interface AZViewController ()

@end

@implementation AZViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    /*
            刷新UI操作,必须在主线程中进行
     
            开启多线程,在iOS中有三种方法开启多线程
     
        1:NSThread            最接近底层   但是这种线程是不安全的
        2:NSOperation       更好用,线程安全
        3:GCD                    和NSOperation一样,更好用,线程安全
     
     
     
        */
    
    
    [self createNSThread];
    
    //第二种
    [self createNSOperation];
    
}

-(void)createNSThread
{
    UIButton *btn =[UIButton buttonWithType:UIButtonTypeSystem];
    btn.frame=CGRectMake(10, 40, 300, 20);
    [btn setTitle:@"开启线程-- NSThread" forState:UIControlStateNormal];
    
    [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
}
-(void)createNSOperation
{
    UIButton *btn =[UIButton buttonWithType:UIButtonTypeSystem];
    btn.frame=CGRectMake(10, 100, 300, 20);
    [btn setTitle:@"开启线程-- NSNSOperation" forState:UIControlStateNormal];
    
    [btn addTarget:self action:@selector(btnOperationClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
}
-(void)btnClick:(UIButton *)btn
{
#if 0
    //休眠主线程,可以看到只有当休眠2s后,btn的高亮才会消失,这既是,刷新UI操作,都是在主线程中完成的。
    [self first];
    [self second];
    
#endif
    
    //开辟子线程  对象方法、类方法
    
    
    //对象方法 创建子线程
    NSThread *thread=[[NSThread alloc] initWithTarget:self selector:@selector(doThing) object:nil];
    //线程名字
    thread.name=@"休眠1s";
    //线程优先级
    thread.threadPriority=0.5;
    [thread start];
    
    
    
    //类方法 创建子线程
    [NSThread detachNewThreadSelector:@selector(doThing1) toTarget:self withObject:nil];
    
}
#pragma mark -- 队列响应
-(void) btnOperationClick:(UIButton *)btn
{
    //创建操作队列
    NSOperationQueue *quene=[[NSOperationQueue alloc] init];
    
    //设置队列的最大操作数--( 并行执行 )
    quene.maxConcurrentOperationCount=10;
    
    /*
        //创建操作
        //有三种方式 
        1:NSInvocationOperation 
        2:NSBlockOperation
        3:  自定义操作
     */
    
    //第一种  NSInvocationOperation
    NSInvocationOperation *operation=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doThing1) object:nil];
    
    //将操作加入到队列中
    [quene addOperation:operation];
    
    
    //第二种  NSBlockOperation
    NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
        [self third];
    }];
    [quene addOperation:blockOperation];
    
   
    //第三中 自定义操作
    /**
                自定义操作,由于是继承自NSOperation,所以我们可以在自定义操作中,设置成员变量,或属性,方法。这样的话,逻辑更加清晰。
        */
    AZMyOperation *myOperation=[[AZMyOperation alloc] init];
    [quene addOperation:myOperation];
}

-(void)doThing
{
    [self first];
    
    //返回主线程中执行执行  ---  func
    [self performSelectorOnMainThread:@selector(func) withObject:nil waitUntilDone:NO];
    
    [self second];
}
-(void)doThing1
{
    [self second];
}
-(void)first
{
    //休眠主线程
    sleep(1);
    NSLog(@"1");
}
-(void)second
{
    sleep(2);
    NSLog(@"2");
}
-(void)third
{
    sleep(3);
    NSLog(@"3");
}

-(void)func
{
    NSLog(@"主线程执行:子线程已经结束");
}
@end</span><span style="font-size: 18px;">
</span>


第三种  GCD


有两种方式实现GCD.

     

       第一种 使用线程队列,有两个步骤,

      

             第一步:创建线程队列

             第二步:异步执行线程队列

     

     

     

       第二种 使用线程组(常用,当线程组中,可以有通知主线程的方法),有三个步骤

             第一步:创建线程组

             第二步:创建线程队列

             第三步:将线程队列放到线程组种,异步执行线程组



第一种方式: 线程队列

    

    

        //01 创建线程队列

    dispatch_queue_t thread=dispatch_queue_create(NULL, NULL);

    

        //02 异步执行线程队列(也就是在,在这个线程队列中,要做什么事)

    dispatch_async(thread, ^{

        sleep(2);

        NSLog(@"休眠2s");

    });

    

    

        //也可以通过  dispatch_get_global_queue(0, 0)  得到闲置的线程队列,如果没有,则会自动创建一个现场队列。

    

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        sleep(2);

        NSLog(@"休眠2s");

    });




    

第二种方式:线程组


    

    //01 创建线程组

    dispatch_group_t threadGroup=dispatch_group_create();

    

    

    //02 创建线程队列

    dispatch_queue_t t=dispatch_queue_create(NULL, NULL);

    

    //03 将线程队列放入到线程组中,

    

    dispatch_group_async(threadGroup, t, ^{

        sleep(2);

        NSLog(@"休眠2s");

    });

    

    //这里又可使用闲置线程队列

    

    dispatch_group_async(threadGroup, dispatch_get_global_queue(0, 0), ^{

        sleep(2);

        NSLog(@"休眠2s");

    });

    

    

    /*

        使用线程组有一个好处就是  当线程组的线程队列已经全部执行完毕后 可以通知  主线程

     */

    

     dispatch_group_notify(threadGroup, dispatch_get_main_queue(), ^{

         NSLog(@"线程组的线程队列已经全部执行完毕。回到主线程");

     });

    

    

    //验证 是否是线程组中的线程队列全部执行完毕后,才调用  通知的

    

    //经过验证 的确是当线程组中的线程队列全部执行完毕后,才开始  通知

     dispatch_group_async(threadGroup, dispatch_get_global_queue(0, 0), ^{

         sleep(3);

         NSLog(@"休眠3s");

     });

    



那么在第三方框架中是怎么来使用线程的呢??
ASI:
<span style="font-size:14px;">ASINetworkQueue* queue = [[ASINetworkQueue alloc] init];
    queue.maxConcurrentOperationCount = 1;
    for (int i = 0; i < 5; i++) {
        ASIHTTPRequest* request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://10.0.8.8/my/sns/user_list.php"]];
        [queue addOperation:request];
    }
    [queue go];
    
    NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://10.0.8.8/my/sns/user_list.php"]];
    NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init];
    //发送一个异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:operationQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        
    }];</span><span style="font-size: 18px;">
</span>

AFNetWork:
<span style="font-size:14px;"> NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com/img/bdlogo.png"]];
    _operation=[[AFHTTPRequestOperation alloc] initWithRequest:request];
    
    [_operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"成功");
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"失败");
    }];
    
    
    //设置保存路径
    NSString *path=[NSString stringWithFormat:@"%@/Documents/a.png",NSHomeDirectory()];
    NSLog(@"%@",path);
    
    //设置操作输出流
    _operation.outputStream=[NSOutputStream outputStreamToFileAtPath:path append:NO];
    
    
    __weak UIProgressView *PV=self.progress;
    
    
    //设置下载进度
    [_operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
#if 0
        [self.progress setProgress:(float)totalBytesRead/totalBytesExpectedToRead animated:YES];
#endif
        //注意在block中有警告的话,可以在外面
        //__weak UIProgressView *PV=self.progress;
        [PV setProgress:(float)totalBytesRead/totalBytesExpectedToRead animated:YES];
    }];
	
    //开始操作
    [_operation start];
</span>







// [NSOperationQueue mainQueue];主线程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值