MST

星途 面试题库

面试题:Objective-C集合框架在多线程环境下的应用与问题解决

假设你正在开发一个多线程的Objective-C应用程序,其中会频繁操作NSArray和NSDictionary。请分析在多线程环境下使用这些集合框架可能会出现哪些问题?如何通过锁机制、GCD(Grand Central Dispatch)或其他技术手段来保证数据的一致性和线程安全?请给出具体的代码示例及分析。
34.8万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

多线程环境下NSArray和NSDictionary可能出现的问题

  1. 数据竞争:多个线程同时读写集合,可能导致数据不一致。例如,一个线程正在遍历NSArray,另一个线程同时对其进行添加或删除操作,可能会引发崩溃或未定义行为。
  2. 内存管理问题:不同线程对集合内对象的内存管理操作不一致,可能导致对象过早释放或内存泄漏。

通过锁机制保证线程安全

  1. 使用NSLock
NSLock *arrayLock = [[NSLock alloc] init];
NSMutableArray *myArray = [NSMutableArray array];

// 线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [arrayLock lock];
    [myArray addObject:@"Object 1"];
    [arrayLock unlock];
});

// 线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [arrayLock lock];
    id obj = [myArray objectAtIndex:0];
    NSLog(@"Object: %@", obj);
    [arrayLock unlock];
});

分析:NSLock是一种简单的互斥锁,通过lockunlock方法来保护对myArray的操作,确保同一时间只有一个线程能访问和修改数组,从而保证数据一致性。

  1. 使用@synchronized
NSMutableDictionary *myDict = [NSMutableDictionary dictionary];

// 线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    @synchronized (myDict) {
        [myDict setObject:@"Value 1" forKey:@"Key 1"];
    }
});

// 线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    @synchronized (myDict) {
        id value = [myDict objectForKey:@"Key 1"];
        NSLog(@"Value: %@", value);
    }
});

分析:@synchronized块会自动为传入的对象(这里是myDict)创建一个锁,在块内的代码执行期间,其他线程无法进入相同对象的synchronized块,保证了对字典操作的线程安全。

通过GCD保证线程安全

  1. 使用串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serialQueue", DISPATCH_QUEUE_SERIAL);
NSMutableArray *myArray = [NSMutableArray array];

// 线程1
dispatch_async(serialQueue, ^{
    [myArray addObject:@"Object 1"];
});

// 线程2
dispatch_async(serialQueue, ^{
    id obj = [myArray objectAtIndex:0];
    NSLog(@"Object: %@", obj);
});

分析:通过创建一个串行队列,所有提交到该队列的任务会顺序执行,避免了多个线程同时操作myArray,从而保证了线程安全。

  1. 使用队列同步
NSMutableDictionary *myDict = [NSMutableDictionary dictionary];
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t syncQueue = dispatch_queue_create("com.example.syncQueue", DISPATCH_QUEUE_CONCURRENT);

// 线程1
dispatch_async(globalQueue, ^{
    dispatch_barrier_async(syncQueue, ^{
        [myDict setObject:@"Value 1" forKey:@"Key 1"];
    });
});

// 线程2
dispatch_async(globalQueue, ^{
    dispatch_sync(syncQueue, ^{
        id value = [myDict objectForKey:@"Key 1"];
        NSLog(@"Value: %@", value);
    });
});

分析:dispatch_barrier_async会等待之前提交到syncQueue的任务执行完毕,并且在它执行期间,其他并行任务无法进入syncQueue,保证了写操作的原子性。dispatch_sync则用于同步读取操作,确保读取时数据的一致性。