MST

星途 面试题库

面试题:Objective-C享元模式在多线程环境下的优化

在Objective-C中,当使用享元模式的系统处于多线程环境时,可能会出现哪些问题?请详细阐述如何对享元模式进行优化以适应多线程场景,给出具体的代码示例说明线程安全的实现方式。
35.6万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

多线程环境下享元模式可能出现的问题

  1. 数据竞争:多个线程同时访问和修改享元对象的内部状态时,可能导致数据不一致。例如,享元对象中保存了一些计数器或者状态变量,多个线程同时对其进行增减操作,会得到错误的结果。
  2. 资源共享冲突:如果享元对象依赖外部资源(如文件、数据库连接等),多线程同时访问这些资源可能会导致资源争用问题,如文件读写混乱、数据库连接异常等。

优化享元模式以适应多线程场景的方法

  1. 使用锁机制:在访问享元对象的共享状态时,使用互斥锁(NSLock@synchronized等)来保证同一时间只有一个线程可以访问和修改共享状态。
  2. 不可变对象:将享元对象设计为不可变对象,这样就无需担心多线程对其状态的修改问题。一旦创建,对象的状态就不再改变。

代码示例 - 使用 @synchronized 实现线程安全

#import <Foundation/Foundation.h>

// 享元工厂类
@interface FlyweightFactory : NSObject

@property (nonatomic, strong) NSMutableDictionary<NSString *, id> *flyweights;

+ (instancetype)sharedFactory;
- (id)getFlyweightWithKey:(NSString *)key;

@end

@implementation FlyweightFactory

+ (instancetype)sharedFactory {
    static FlyweightFactory *factory = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        factory = [[FlyweightFactory alloc] init];
        factory.flyweights = [NSMutableDictionary dictionary];
    });
    return factory;
}

- (id)getFlyweightWithKey:(NSString *)key {
    @synchronized(self) {
        id flyweight = self.flyweights[key];
        if (!flyweight) {
            flyweight = [[NSObject alloc] init]; // 实际应用中这里创建具体的享元对象
            self.flyweights[key] = flyweight;
        }
        return flyweight;
    }
}

@end

// 测试代码
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FlyweightFactory *factory = [FlyweightFactory sharedFactory];
        // 模拟多线程环境
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_group_t group = dispatch_group_create();
        for (int i = 0; i < 10; ++i) {
            dispatch_group_async(group, queue, ^{
                id flyweight = [factory getFlyweightWithKey:@"key"];
                NSLog(@"Thread %ld got flyweight: %@", (long)[NSThread currentThread].threadIdentifier, flyweight);
            });
        }
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    }
    return 0;
}

代码示例 - 使用 NSLock 实现线程安全

#import <Foundation/Foundation.h>

// 享元工厂类
@interface FlyweightFactory : NSObject

@property (nonatomic, strong) NSMutableDictionary<NSString *, id> *flyweights;
@property (nonatomic, strong) NSLock *lock;

+ (instancetype)sharedFactory;
- (id)getFlyweightWithKey:(NSString *)key;

@end

@implementation FlyweightFactory

+ (instancetype)sharedFactory {
    static FlyweightFactory *factory = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        factory = [[FlyweightFactory alloc] init];
        factory.flyweights = [NSMutableDictionary dictionary];
        factory.lock = [[NSLock alloc] init];
    });
    return factory;
}

- (id)getFlyweightWithKey:(NSString *)key {
    [self.lock lock];
    id flyweight = self.flyweights[key];
    if (!flyweight) {
        flyweight = [[NSObject alloc] init]; // 实际应用中这里创建具体的享元对象
        self.flyweights[key] = flyweight;
    }
    [self.lock unlock];
    return flyweight;
}

@end

// 测试代码
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FlyweightFactory *factory = [FlyweightFactory sharedFactory];
        // 模拟多线程环境
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_group_t group = dispatch_group_create();
        for (int i = 0; i < 10; ++i) {
            dispatch_group_async(group, queue, ^{
                id flyweight = [factory getFlyweightWithKey:@"key"];
                NSLog(@"Thread %ld got flyweight: %@", (long)[NSThread currentThread].threadIdentifier, flyweight);
            });
        }
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    }
    return 0;
}

以上两种方式都通过加锁保证了享元对象在多线程环境下的安全访问,@synchronized 语法糖内部也是基于锁机制实现,而 NSLock 则是更显式的锁操作。在实际应用中,可根据具体场景选择合适的方式。