Bison眼中的iOS开发多线程是这样的(二)

少于 1 分钟 阅读

"多线程很容易突然出现“错误情况”,这是由于系统的线程调度具有一定的随机性造成的。不过,即使程序偶然出现问题,那也是由于编程不当所引起的。当使用多个线程来访问同一个数据时,很容易“偶然”出现线程安全问题。"

前面在《Bison眼中的iOS开发多线程是这样的(一)》一文中讲到多线程的优先级,接下来我什么讲讲线程同步与线程通信
多线程很容易突然出现“错误情况”,这是由于系统的线程调度具有一定的随机性造成的。不过,即使程序偶然出现问题,
那也是由于编程不当所引起的。当使用多个线程来访问同一个数据时,很容易“偶然”出现线程安全问题。

关于线程安全问题,有OC的多线程支持引入了同步,使用同步的通用方法就是@synchronized修饰代码块,
@synchronized修饰的代码块可简称为同步代码块。同步代码块的语法格式如下:

@synchronized(obj){
    ...
    //此处的代码即为同步代码块
}

上面语法格式中@synchronized后面括号里的obj就是同步监视器。上面代码的含义是:
线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。值得注意的是,人和时刻只能有
一个线程可以获得对同步监视器的锁定,当同步代码块执行完后,该线程会释放对同步监视器的锁定
虽然OC允许使用任何对象作为同步监视器,但想一下同步监视器的目的:阻止俩个线程对同一共享资
源进行并发访问,因此通常推荐使用可能被并发访问的共享资源充当同步监视器

线程安全的类具有如下特征:

该类的对象可以被多个线程安全的访问。

每个线程调用该对象的任意方法之后都将得到正确结果。

每个线程调用该对象的任意方法之后,该对象依然保持合理状态。

Foundation框架中很多类都是有可变和不可变俩种版本,其中不可变类总是线程安全的,因为它的
对象状态不可改变。而可变类的对象需要额外的方法来保证其线程安全。
将多个线程并发修改共享资源的临界区使用@synchronized修饰,这样即可保证任意时刻,最多只
能有一个线程进入临界区修改共享数据,从而就可以实现线程安全的类。
可变类的线程安全是以降低程序的运行效率作为代价的。为了减少线程安全所带来的负面影响,程序可
以采用如下策略:

不要对线程安全类的所有方法都进行同步,只对那些会改变竞争资源(共享资源)对方法进行同步。

如果可变类有俩种运行环境:单线程环境和多线程环境,则应该为该可变类提供俩种版本,线程不安全版本和安全版本。在单线程环境中使用线程不安全版本已保证性能,在多线程环境中使用线程安全版本。

任何线程在进入同步代码块之前,必须先获得对同步监视器的锁定,那么何时会释放对同步监视器的锁定呢?程序无法显示释放对同步监视器的锁定,线程会再如下几种情况下释放对同步监视器的锁定。

当线程的同步代码块执行结束,当前线程即将释放同步监视器。

当线程的同步代码块中遇到 goto、 return终止了该代码块、该方法的继续执行时,当前线程将会释放同步监视器。

当线程的同步代码块中出现了错误,导致该代码块异常结束时,将会释放同步监视器。典型的例子有:当程序调用NSThreadsleepXxx方法暂停线程时,线程不会释放同步监视器。

Foundation还提供了NSLock,通过显示定义同步锁对象来实现同步,在这种机制下,同步锁使用NSLock对象充当。

NSLock是控制多个线程对共享资源进行访问的工具。通常锁提供了对共享资源的独占访问,每次只能有一个线程对NSLock对象加锁,线程开始访问共享资源之前应县获得NSLock对象。

在实现线程安全的控制中,使用该NSLock对象可以显式的加锁、释放锁。下面我们来举个简单的🌰

NSLock* lock;
- (id)init
{
    self = [super init];
    if (self) {
        lock = [[NSLock alloc] init];
    }
    return self;
}

//定义需要保证线程安全的方法
- (void)Safety{
    
    [lock lock];

    //需要保证线程安全的方法
    
    [lock unlock];
}


当线程在系统内运行,线程的调度具有一定的透明度,程序通常无法准确控制线程的轮换执行,但我们可以通过一些机制来保证线程协调运行,也就是处理线程之间的通信。

对此Foundation提供了NSCondition类来处理多线程之间的通信,NSCondition实现了NSLock协议,因此也可以调用lockunlock来实现线程同步。除此之外,NSCondition可以让那些已经锁定NSCondition对象却无法继续执行的线程释放NSCondition对象,NSCondition对象也可以唤醒其他处于等待状态的线程。

NSCondition提供了如下几个方法

//改方法导致当前线程一直等待,直到其他线程调用该NSCondition的signal方法或者broadcast方法 
- (void)wait;
//用于控制等待到指定时间点,如果到了该时间点,该线程将会被自动唤醒
- (BOOL)waitUntilDate:(NSDate *)limit;
//唤醒等待的单个线程,如果有多个,则随机唤醒一个。只有当前线程放弃对该NSCondition对象的锁定后(wait方法),才可执行
- (void)signal;
//唤醒等待的所有线程
- (void)broadcast;

今天暂时写到这!
预告:(三)主讲GCD多线程!


博主app上线啦,快点此来围观吧

原文地址:http://allluckly.cn

好文推荐:详解持久化Core Data框架的原理以及使用

版权归©Bison所有 如需转载请保留原文超链接地址!否则后果自负!