iOS使用多线程提高数据并发访问之六-创新互联
线程的风险
创新互联公司主营夏县网站建设的网络公司,主营网站建设方案,App定制开发,夏县h5微信小程序开发搭建,夏县网站营销推广欢迎夏县等地区企业咨询当运行在一个多线程环境中,你总是需要注意一些事情:你不能控制线程执行的顺序。例如,如果你有两个线程,线程1和线程2,CPU可能会在线程1上运行一段时间,然后又会切到线程2运行一段时间。问题是你不知道CPU何时切过去,也不知道会为一个线程分配多少时间。每个线程运行的时间都不是公平的。
为了演示线程不容易控制带来的风险,我会举一个例子。这个例子包括两个线程:线程1和线程2. 线程1打印奇数,线程2打印偶数。这些数的范围从1到20. 线程1先启动,然后线程2再启动。这个例子将会运行3次。Listing 6-5 显示了样例代码。
正如你看到的,我先调用打印奇数,然后再打印偶数。你可能会期待看到
先打印一些奇数
奇数和偶数平均打印,例如两个奇数和两个偶数
但是,这些猜测都是不正确的,你可以看表格 6-4, 显示了3次运行的结果。
你看下第2次,0先打印出来,而其他的都是先打印1。奇数和偶数打印也不是平均的;而且,也没什么迹象表明有多少奇数在偶数之前打印。
因此,在多线程环境中,你不能控制线程执行的顺序。多线程是一把双刃剑。开发者实现一个多线程应用需要注意下面的3个风险。
安全性:这个标准意味着在多线程环境下,输出要跟预期的一致。换句话说,程序可以运行在不同的顺序中多次,但是最终的输出必须是可预见的,正确的。“糟糕的事情不会发生”。
活跃性:这个和安全性不同。一种定义是“一些好的情况最终会发生”。例如,假设线程A必须等到线程B的结果,有时这些结果从来都不返回。因此,线程A从来不会计算最终结果。这个通常称为死锁。
性能:iPhone应用最重要的一个目标就是有一个比较好的性能和更灵敏的UI。因此,你的性能目标必须达到。活跃性只关注一些最终发生的事情;它并不关心多快获取到结果。
我将会在接下来的部分使用例子来涉及到每一个标准,这样你就可以理解什么样会导致一个不好的结果,你如何解决它,使得你的应用运行时有一个比较高的性能。
安全性
安全性要求程序运行在多线程环境中,产生一个正确的期待的结果,就想他运行在单线程环境中一样。我会讨论一个潜在的在多线程环境中经常会发生的一个问题,当两个或多个线程同时访问相同的数据。
图 6-5 描述了两个线程如何返回一个相同的item而导致应用崩溃。在图6-5中,线程1尝试把item push到当前栈中。然后,线程2和线程3想要把item取出来,然后检查确保这个item在这个栈中。但是,在两个线程检查之后,线程2先运行,然后获取item。Oops!像你看到的,线程3已经没有item可以获取了。这会导致你的应用崩溃。
你可以从ThreadSafety工程中获取到样例代码,但是Listing 6-6 显示了这个问题的代码注解。注意这个问题不会总是出现,但是如果你运行足够多的时间,它还是会发生的。代码使用了NSMutableArray变量存储,因此客户端代码能够添加和删除数据。
当你运行上面的代码一段时间,你会收到下面的信息:
它告诉你,你尝试在一个空的数组中删除对象,这是不应该发生的当你在删除之前已经检查了数组空的情况。你甚至打印出来看它是否是最后一个对象。
现在,如果你再一次查看图6-4,你应该理解为什么会崩溃 -- 因为第一个现场检查和打印出最后一个对象后,第一个线程已经停止,而第二个线程还在运行。
解决办法
对于这个问题我的解决办法是锁住这个方法直到线程执行完。锁是一种机制,它能够确保在一个时间内只有一个线程访问一个指定的代码块。想象一下,你现在在一个比赛中,需要直接和很多人竞争。你和你的竞争者被问了一个问题,而谁先响铃谁就能先回答问题。在第一个结束之后,另外一个人又可以摇铃了。当第一个人在回答问题时,这个铃是被锁住的。线程也是一样的。你可以创建一个锁,就像是你的铃一样:第一个得到锁的线程(类似摇铃)会阻塞其他所有的线程直到它结束。在第一个线程结束之后,锁就开了(类似于其他人可以摇铃了);其他线程能尝试获取锁,而这个过程可以重复下去。
锁机制的基本概念就是确保当一个线程在执行任务时,其他线程不能打断。例如,如果线程1获取到这个对象,然后打印出来,线程2必须等到线程1执行完才能获取和从数组中删除对象。
这个锁创建在一个对象上。如果线程1从对象A获取了锁,其他线程就不能再获取这个对象的锁了,这些线程必须等待线程1执行完后,然后把锁返回给对象A。
最简单的方式获取对象A的锁的就是使用@synchronized(objA),如下面Listing 6-7 的代码。
注意:在很多情况下,使用self作为锁,效果是一样的。你只需要确保你想要锁住的对象使用同一个对象锁即可。例如,你有两个存储变量,你可以考虑为每一个单独是有关一个锁。 |
图6-6 显示了@synchronized在线程中是如何工作的。
你需要同时同步push和pop data这两个方法,因为如果你只锁住其中的一个方法,当你pop检查时,依然会存在风险,还有存储器push了很多数据,而你不没有按照你想要的方式获取到对象。为了防止这些,你需要使用lockObj同时锁住他们,这样在一个时间段就只有一个方法在运行。
你的代码是安全的,但是依然还有两个更重要的多线程属性需要讨论。
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
网页标题:iOS使用多线程提高数据并发访问之六-创新互联
当前网址:http://azwzsj.com/article/cdohsi.html