iOS---多线程总结

image.png
image.png
image.png
image.png

死锁的原因:队列引起的循环等待


image.png

逻辑:在主队列中提交了viewDidLoad任务,然后提交 block任务,这2个任务最终都需要分派的主线程中执行。比如说分派 viewDidLoad到主线程中处理,在执行过程当中,需要调用block, 当block同步调用完成后,viewDidLoad方法才能继续向下执行,所以viewDidLoad调用结束或者说处理需要依赖于后续提交的block任务。主队列的性质是先进先出,Block任务要执行,依赖于 viewDidLoad任务完成。这个过程就造成死锁。

image.png
image.png

逻辑:以上代码涉及2个队列,一个是主队列,一个是串行队列。
在viewDidLoad运行在主线程中,viewDidLoad执行到某一时刻时,需要同步提交任务到对应的串行队列上。同步提交,意味着在当前线程执行。所以串行队列提交的任务,最终也是在主线程中执行,串行队列中提交的任务在主线程当中执行完成后,才去继续执行主队列viewDidLoad后续的代码逻辑.

结论: 同步方式提交的任务,是在当前线程执行

image.png
image.png
image.png

结果:13
解析:通过异步方式分派到全局并发队列,block本身会在GCD底层所维护的线程池当中的某一线程上去执行。而关于GCD的线程,默认情况下是不开启对应RunLoop的。performSelector即使延迟0秒,也需要提交相应的任务到RunLoop上的逻辑。performSelector方法调用,也是需要有对应的RunLooop的。

Q:怎样利用GCD实现多读单写?
A:


image.png
image.png
image.png
image.png
image.png

dispatch_group_async()

这个是最简单的,这里就不详诉了。

NSOperation

如果希望通过NSOperation实现多线程技术,需要结合NSOperationQueue。


image.png

任务执行状态控制

isReady: 是否就绪
isExecuting: 是否处于正在执行中的状态
isFinished: 当前任务是否已执行完成
isCancelled: 当前任务是否已取消

状态控制

image.png

底层代码实现:


image.png
image.png
image.png
image.png
image.png

Q:系统怎样移除一个isFinished=YES的NSOperation的?
A:通过KVO。

延伸Q:KVO机制和特性?

NSThread

image.png
image.png
image.png
image.png
image.png

Q:iOS中有哪些锁?/ 日常开发中都使用过哪些锁,是怎么使用的?
A:@synchronized, atomic, OSSpinLock, NSRecursiveLock, NSLock, dispatch_semaphore_t

@synchronized: 一般在创建单例对象的时候使用,来保证在多线程环境下创建对象是唯一的。

互斥锁:
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量cpu资源
使用前提:多条线程抢夺同一块资源

以下是使用@synchronized加锁卖票的示例:

@implementation ViewController {
    
    NSInteger _tickets;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    _tickets = 100;
    
    // 1.开启一条售票线程
    NSThread * thread_1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
    thread_1.name = @"售票 A";
    [thread_1 start];
    
    // 2.再开启一条售票线程
    NSThread * thread_2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
    thread_2.name = @"售票 B";
    [thread_2 start];
}

- (void)saleTickets {
    
    while (YES) {
        
        @synchronized (self) {
            
            if (_tickets > 0) {
                
                _tickets--;
                
                NSLog(@"剩余票数%ld %@",(long)_tickets,[NSThread currentThread]);
                
            } else {
                
                NSLog(@"票卖完了");
                
                break;
            }
        }
    }
}

atomic:
1). 修饰属性的关键字
2). 对被修饰对象进行原子操作(赋值操作保证安全,使用不能保证安全)
示例如下:


image.png

OSSpinLock(自旋锁):
循环等待询问,不释放当前资源。
应用场景:用于轻量级数据访问,简单的int值+1/-1操作。

NSLock:


image.png

Q:以上代码有什么问题?
A:methodA, 加锁后,methodB又对同一把锁进行加锁,就相当于已经获取到了锁,又再次获取这个锁,就会由于重入的原因导致死锁。可以使用递归锁NSRecursiveLock。


IMG_6255.jpg

dispatch_semaphore_t:
参数如下:

//根据一个初始值创建信号量
dispatch_semaphore_create(信号量值)
//如果信号量的值<=0,当前线程就会进入休眠等待(直到信号量的值>0);如果信号量的值>0,就减1,然后往下执行后面的代码。
dispatch_semaphore_wait(信号量,等待时间)
//提高信号量(让信号量的值加1)
dispatch_semaphore_signal(信号量)
image.png
image.png
image.png
image.png

你可能感兴趣的:(iOS---多线程总结)