摘要:如果没有采用合适的同步机制,线程间的交叉执行情况就无法预料。当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竞态条件发生的代码区称作临界区。
在同一程序中运行多个线程本身不会导致问题,问题在于多个线程访问了相同的资源。如,同一内存区(变量,数组,或对象)、系统(数据库,web services等)或文件。实际上,这些问题只有在一或多个线程向这些资源做了写操作时才有可能发生,只要资源没有发生变化,多个线程读取相同的资源就是安全的。
多线程同时执行下面的代码可能会出错:
public class Counter { protected long count = 0; public void add(long value){ this.count = this.count + value; } }
想象下线程A和B同时执行同一个Counter对象的add()方法,我们无法知道操作系统何时会在两个线程之间切换。JVM并不是将这段代码视为单条指令来执行的,而是按照下面的顺序:
从内存获取 this.count 的值放到寄存器
将寄存器中的值增加value
将寄存器中的值写回内存
观察线程A和B交错执行会发生什么:
this.count = 0; A: 读取 this.count 到一个寄存器 (0) B: 读取 this.count 到一个寄存器 (0) B: 将寄存器的值加2 B: 回写寄存器值(2)到内存. this.count 现在等于 2 A: 将寄存器的值加3 A: 回写寄存器值(3)到内存. this.count 现在等于 3
两个线程分别加了2和3到count变量上,两个线程执行结束后count变量的值应该等于5。然而由于两个线程是交叉执行的,两个线程从内存中读出的初始值都是0。然后各自加了2和3,并分别写回内存。最终的值并不是期望的5,而是最后写回内存的那个线程的值,上面例子中最后写回内存的是线程A,但实际中也可能是线程B。如果没有采用合适的同步机制,线程间的交叉执行情况就无法预料。
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竞态条件发生的代码区称作临界区。上例中add()方法就是一个临界区,它会产生竞态条件。在临界区中使用适当的同步就可以避免竞态条件。
原文 Race conditions and critical sections
翻译 He Jianjun 校对 丁一
via ifeve
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/64055.html
摘要:父进程调用创建子进程。因而,一个进程的第一个线程会随着这个进程的启动而创建,这个线程被称为该进程的主线程。另一方面,线程不可能独立于进程存在。终止线程线程可以通过多种方式来终结同一个进程中的其他线程。 前言 不积跬步,无以至千里;不积小流,无以成江海。在学习Java多线程相关的知识前,我们首先需要去了解一点操作系统的进程、线程以及相关的基础概念。 进程 通常,我们把一个程序的执行称为一...
摘要:并发需要解决的问题功能性问题线程同步面临两个问题,想象下有两个线程在协作工作完成某项任务。锁可用于规定一个临界区,同一时间临界区内仅能由一个线程访问。并发的数据结构线程安全的容器,如等。 并发指在宏观上的同一时间内同时执行多个任务。为了满足这一需求,现代的操作系统都抽象出 线程 的概念,供上层应用使用。 这篇博文不打算详细展开分析,而是对java并发中的概念和工具做一个梳理。沿着并发模...
阅读 1482·2021-11-22 09:34
阅读 1636·2019-08-29 16:36
阅读 2627·2019-08-29 15:43
阅读 3072·2019-08-29 13:57
阅读 1268·2019-08-28 18:05
阅读 1853·2019-08-26 18:26
阅读 3212·2019-08-26 10:39
阅读 3348·2019-08-23 18:40