线程进程安全概述(PPT 44页).ppt

  1. 1、本文档共44页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
不同语言中,同步代码段的实现模型类似,只是表达方式有些不同。这里以Java语言为例,在Java语言中,synchronized关键字可以解决这个问题,整个语法形式表现为: 注意,synchronized后的“同步锁对象”,必须是可以被各个线程共享的,如this、某个全局标量等。不能是一个局部变量。 其原理为:当某一线程运行同步代码段时,在“同步锁对象”上置一标记,运行完这段代码,标记消除。其他线程要想抢占CPU运行这段代码,必须在“同步锁对象”上先检查该标记,只有标记处于消除状态,才能抢占CPU。在上面的例子中,this是一个“同步锁对象”。 synchronized(同步锁对象) { // 访问共享资源,需要同步的代码段 } * 因此,在上面的案例中,可以将将卖票的代码用synchronized代码块包围起来,“同步锁对象”取this。 如代码P03_05.java所示。 运行,可以得到如下效果。 * 这说明程序运行完全正常。 从以上代码可以看出,该方法的本质是将需要独占CPU的代码用synchronized(this)包围起来。如前所述,一个线程进入这段代码之后,就在this上加了一个标记,直到该线程将这段代码运行完毕,才释放这个标记。如果其他线程想要抢占CPU,先要检查this上是否有这个标记。若有,就必须等待。 但是可以看出,该代码实际上运行较慢,因为一个线程的运行,必须等待另一个线程将同步代码段运行完毕。因此,从性能上讲,线程同步是非常耗费资源的一种操作。我们要尽量控制线程同步的代码段范围,理论上说,同步的代码段范围越小,段数越少越好,因此在某些情况下,推荐将小的同步代码段合并为大的同步代码段。 * 实际上,在Java内,还可以直接把synchronized关键字直接加在函数的定义上,这也是一种可以推荐的方法。 不过,值得一提的是,如果不能确定整个函数都需要同步,那就要尽量避免直接把synchronized加在函数定义上的做法。如前所述,要控制同步粒度,同步的代码段越小越好,synchronized控制的范围越小越好,否则造成不必要的系统开销。所以,在实际开发的过程中,要十分小心,因为过多的线程等待可能造成系统性能的下降,甚至造成死锁。 * 3.3 线程协作安全 * 3.3.1 线程协作 有些情况下,多个线程合作完成一件事情的几个步骤,此时线程之间实现了协作。如一个工作需要若干个步骤,各个步骤都比较耗时,不能因为它们的运行,影响程序的运行效果,最好的方法就是将各步用线程实现。但是,由于线程随时都有可能抢占CPU,可能在前面一个步骤没有完成时,后面的步骤线程就已经运行,该安全隐患造成系统得不到正确结果。 * 3.3.2 案例分析 给出一个案例:线程1负责完成一个复杂运算(比较耗时),线程2负责得到结果,并将结果进行下一步处理。如:某个科学计算系统中,线程1负责计算1-1000各个数字的和(暂且认为它非常耗时),线程2负责得到这个结果并且写入数据库。 读者首先想到的是将耗时的计算放入线程。这是正确的想法。首先用传统线程方法来编写这段代码,代码如P03_06.java所示。 * 该程序貌似没有问题,也能够打印正确结果,但是和上一节的例子一样,它也是很不安全的,这种不安全性也很难发现,也会给项目后期维护带来巨大的代价。该程序的安全隐患在哪里呢? 观察cal()函数中的代码,当线程th1运行后,线程th2运行,此时,线程th2随时可能抢占CPU,而不一定要等线程th1运行完毕。当然,在上面的例子中,可能因为线程th1运行较快,th2在它运行的过程中没有抢占CPU,“碰巧”得到了正确结果,但是如果让线程th2抢占CPU,这样,系统可能得不到正确结果。为了解释这个问题,将P03_06.java的代码改为P03_07.java * 该代码中,增加了一行:程序休眠1毫秒,让另一个线程来抢占CPU。运行,控制台打印如下: 很显然,这个结果不是我们所需要的。 那为什么sum得到的结果为1呢?很明显,线程th1的start函数运行时,相当于让求和过程以多线程形式运行,在它“休眠”之际,th2就抢占了CPU,在求和还没开始做或只完成一部分时就打印sum,导致得到不正常结果。 * 3.3.3 解决方案 怎样解决?显而易见,方法是:在运行一个线程时,命令其他线程等待该线程运行完毕,才能抢占CPU进行运行。对于该问题,不同语言解决方法类似。以Java语言为例,在Java语言中,线程的join()方法可以解决这个问题。 见代码P03_08.java 运行正常。实际上,该程序相当于摒弃了“线程就是为了程序看起来同时做好几件事情”的思想,将并发程序又变成了顺序的,如果线程th1没有运行完毕的话,程序会在th.jo

文档评论(0)

138****8882 + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

版权声明书
用户编号:7162041115000004

1亿VIP精品文档

相关文档