ios多线程

一.线程与进程

要理解多线程首先要了解进程与线程的基本概念。

1.进程

进程指的是系统中正在运行的一个应用程序。一个应用一般只会开启一个进层,单有的也会开启多个(比如浏览器),mac的进程的个数可以在活动监视器中查看。

一个进程中的线程是共享内存和资源的。

2.线程

线程是进程的基本单元,进程中的任务都要在线程中执行。(如:下载音乐,播放音乐等)。

每个进程都有一个主线程,主线程的生命周期是和进程一样的,当进程结束时,主线程也就停止了。

3.多线程

多线程是指一个进程中存在多个线程,一般单线程执行任务是串行的,而多线程可以并发执行多个任务(每个线程执行一个任务),所以多线程提高了cpu的利用率,但会使得设计更加复杂。

多线程使用时要注意界面的刷新只能在主线程中进行,所以不要将耗时的任务放在主线程中。

多线程中每个线程的内存大小为都为512kb,要注意内存的管理。(ps:很多地方说主线程是1m,我自己试了一下是512kb,待会在下面会给出程序,如果不对请大家改正)


二.多线程的三种技术

1.NSThread

优点:NSThread量级轻,使用简单

缺点:需要自己管理线程的生命周期,线程同步,加锁等

2.NSOperation

不需要关心线程的管理,数据同步。

NSOperation是面向对象的(可以复用,封装,子类化)抽象程度高,接口简单,可读性强,在项目较复杂的情况下使用较好。

3.GCD

GCD是ios4以后推出的多线程技术,是基于C语言的,简单,明了,结合block使用更加简单,在项目较简单时使用比较好。


三.线程的创建

1.NSThread

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //新建一个线程
    //方法一:
    NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(mutableThread:) object:@"thread"];
    [thread1 start]; //手动启动
    
    if([[NSThread currentThread] isMainThread]){
        NSLog(@"是主线程 大小为:%ld",[[NSThread currentThread] stackSize]);
    }
}

- (void)mutableThread:(NSString*)str{
    if([[NSThread currentThread] isMainThread]){
        NSLog(@"是主线程 大小为:%ld",[[NSThread currentThread] stackSize]);
        
    }else{
        NSLog(@"%@,大小为:%ld",str,[[NSThread currentThread] stackSize]);
    }
    //手动退出
    [NSThread exit];
}



输出结果为:所以我得出主线程的内存为512kb的结论。




NSThread创建线程还可以用一下两种方法

[NSThread detachNewThreadSelector:@selector(mutableThread:) toTarget:self withObject:@“thread1”];


[self performSelector:@selector(mutableThread:) withObject:nil afterDelay:0.5];


2.NSOperation

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //创建线程池
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    queue.maxConcurrentOperationCount = 3;//设置多线程最大并发数
    queue.suspended = YES;//所有线程中的任务挂起
    //创建NSOperation
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(thread1Action:) object:@"op1"];
    NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(thread2Action:) object:@"op2"];
    NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(thread3Action:) object:@"op3"];
    NSInvocationOperation *op4 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(thread4Action:) object:@"op4"];
        op1.queuePriority = NSOperationQueuePriorityNormal;
        op2.queuePriority = NSOperationQueuePriorityNormal;
        op3.queuePriority = NSOperationQueuePriorityHigh;
        op4.queuePriority = NSOperationQueuePriorityNormal;

    
        //把operation添加到线程队列中
        [queue addOperation:op1];
        [queue addOperation:op2];
        [queue addOperation:op3];
        [queue addOperation:op4];
        
        queue.suspended = NO;

}
- (void)thread1Action:(NSString *)str{
    NSLog(@"thread1Action %p",[NSThread currentThread]);
    
    for (int i = 0; i<10; i++) {
        NSLog(@"threa1Aciton --- %d",i);
    }
}

- (void)thread2Action:(NSString *)str{
    NSLog(@"thread2Action %p",[NSThread currentThread]);
    for (int i = 0; i<10; i++) {
        NSLog(@"threa2Aciton --- %d”,i);
    }
}
- (void)thread3Action:(NSString *)str{
    NSLog(@"thread3Action %p",[NSThread currentThread]);
    for (int i = 0; i<10; i++) {
        NSLog(@"threa3Aciton --- %d",i);
    }
}
- (void)thread4Action:(NSString *)str{
    NSLog(@"thread4Action %p",[NSThread currentThread]);
    for (int i = 0; i<10; i++) {
        NSLog(@"threa4Aciton --- %d",i);
    }
}

输出结果为:从结果可以看出因为设置子线程3的优先级较高,所以虽然子线程1和子线程2先加入到线程池中,但3先执行。同时因为设置线程最大并发数是3,所以在子线程3执行结束之后才执行子线程4。

同时可以用block语法 给队列中添加操作

[queue addOperationWithBlock:^{

      NSLog(@"thread1Action %p",[NSThread currentThread]);

       

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

         NSLog(@"threa5Aciton --- %d",i);

        }

    }];


3.GCD

GCD有串行队列和全局队列

其中串行队列只会开启一条线程 dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL); 

全局队列可能会开启多条线程,同时执行多个任务(无序),开启的线程数取决于任务数量和内核等


一 使用全局队列  并行队列

    dispatch_queue_t  queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    异步添加:立即返回,不等待block执行完毕

   

 dispatch_async(queue1, ^{
        for (int i = 0; i<10;i++) {
            

            NSLog(@"demo1  %p ----%d",[NSThread currentThread],i);
        }
    });
    dispatch_async(queue1, ^{
        for (int i = 0; i<10;i++) {
            NSLog(@"demo2  %p ----%d",[NSThread currentThread],i);
        }
    });
    同步添加: 等待block执行完毕才返回
    dispatch_sync(queue1, ^{
        for (int i = 0; i<10;i++) {
            NSLog(@"demo2  %p ----%d",[NSThread currentThread],i);

        }
    });
    NSLog(@“添加完毕");


需要注意的是不能在串行队列中同步添加block这种延迟调用的任务,容易造成死锁。例如在主线程中同步添加blck来执行任务,那block就会等待队列中的任务结束再执行,而队列就会等待block执行结束。这样就会相互等待。



三.原子操作

原子操作是为了防止多个线程同时使用同一个资源而造成混乱。

下面以车票为例进行说明

@implementation ViewController{
    //票个数
    int ticket;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    ticket = 30;
    [self performSelectorInBackground:@selector(saleTicket:) withObject:@"thread1"];
    [self performSelectorInBackground:@selector(saleTicket:) withObject:@"thread2"];
    [self performSelectorInBackground:@selector(saleTicket:) withObject:@"thread3"];
}

- (void)saleTicket:(NSString *)str{
    
    while (1) {
        //mutex 信号量
        //原子操作  只有一个人可以进来操作,操作过程中不能被打断
        @synchronized(self){
            NSLog(@"%@ 开始卖票",str);
            if (ticket == 0) {
                break;
            }
            ticket--;
            NSLog(@"%@ 还剩票----%d",str,ticket);
        
       }
    }
   
}


在用关键字@synchronized标记之后里面的程序在同一个时间只能有一个线程执行,避免了执行紊乱。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值