iOS

多线程

2018-07-04  本文已影响0人  NeroXie

所谓多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。

多线程的基本概念

多线程的原理

我们知道,在同一时间内,CPU只能处理一条线程,即只有一条线程在执行。多线程的并发执行,就是CPU在多条线程之间实现快速的调度(切换),使得看起来就好像是一起在执行。

使用多线程可以适当提高程序的执行效率以及资源利用率(CPU、内存利用率),但是开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,就会占用大量的内存空间,降低程序的性能。随着线程数量越多,CPU在调度线程上的开销就越大。

线程的状态与生命周期

线程的生命周期要经过新建就绪运行阻塞死亡5种状态。当创建线程并启动以后,它并不是一启动就进入了运行状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU独自运行,CPU需要在多条线程之间切换,所以线程状态会在运行、阻塞之间多次切换。
如图:

thread_life_cycle.png

多线程实现技术

方案 简介 生命周期 使用频率
pthread 纯C语言,跨平台 程序员管理 几乎不用
NSThread OC语言,使用面向对象的思维,直接操纵线程对象 程序员管理 偶尔使用
GCD 纯C语言,用于取代NSThread,可用充分利用设备的多核 自动管理 经常使用
NSOperation 基于GCD,更面向对象 自动管理 经常使用

多线程安全隐患

资源共享问题:一块资源有可能会被多个线程共享,即多个线程同时访问一个资源。想要解决资源的话,就需要加锁。加锁可以保证当一个线程正在对一块资源进行写操作的时候,这时候是不允许其他的线程对该资源进行访问,只有当该线程访问结束后,其他线程才能按顺序进行访问。

以卖票问题为例,代码如下:

@interface Multithread()

@property (nonatomic, strong) NSThread *thread1;
@property (nonatomic, strong) NSThread *thread2;
@property (nonatomic, strong) NSThread *thread3;

@property (nonatomic, assign) NSInteger ticketCount;

@end

@implementation Multithread

- (instancetype)init {
    if (self = [super init]) {
        self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(_sellTickets) object:nil];
        self.thread1.name = @"thread1";
        
        self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(_sellTickets) object:nil];
        self.thread2.name = @"thread2";
        
        self.thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(_sellTickets) object:nil];
        self.thread3.name = @"thread3";
        
        self.ticketCount = 100;
    }
    
    return self;
}

- (void)begin {
    [self.thread1 start];
    [self.thread2 start];
    [self.thread3 start];
}

- (void)_sellTickets {
    while (self.ticketCount > 0) {
            [NSThread sleepForTimeInterval:1];
            
            if (self.ticketCount > 0) {
                self.ticketCount --;
                NSLog(@"%@买了一张票,还有%ld", [NSThread currentThread].name, self.ticketCount);
            }
    }
}

@end

打印出来的结果:

1.jpg

从上面可以看出打印的余票数据出现错误。

解决方法:

1.互斥锁(同步锁):

- (void)_sellTickets {
    while (self.ticketCount > 0) {
        @synchronized(self) {
            [NSThread sleepForTimeInterval:1];
            
            if (self.ticketCount > 0) {
                self.ticketCount --;
                NSLog(@"%@买了一张票,还有%ld", [NSThread currentThread].name, self.ticketCount);
            }
        }
    }
}

当有线程在执行代码的时候,执行体也就是代码块就会被加锁,等这个线程处理完成后,下一个线程才能使用,相当于将并行改成了串行,另外互斥锁在保护单例的时候可以使用。它的缺点就是消耗性能。

2.NSLock

- (void)_sellTickets {
    while (self.ticketCount > 0) {
        [self.lock lock];
        [NSThread sleepForTimeInterval:1];
        
        if (self.ticketCount > 0) {
            self.ticketCount --;
            NSLog(@"%@买了一张票,还有%ld", [NSThread currentThread].name, self.ticketCount);
        }
        [self.lock unlock];
    }
}
上一篇 下一篇

猜你喜欢

热点阅读