这些Java教程是为JDK 8编写的。本页描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请查看Java语言变化,了解Java SE 9及后续版本中更新的语言功能的概要。
请查看JDK发布说明,了解所有JDK版本的新功能、增强功能以及已删除或弃用选项的信息。
考虑一个简单的类称为Counter
class Counter { private int c = 0; public void increment() { c++; } public void decrement() { c--; } public int value() { return c; } }
Counter
被设计成每次调用increment
都会将c
加1,而每次调用decrement
都会将c
减1。然而,如果一个Counter
对象被多个线程引用,线程之间的干扰可能会阻止按预期进行。
干扰发生在两个操作在不同线程中运行,但作用于相同的数据时进行交错。这意味着两个操作由多个步骤组成,而且步骤序列是重叠的。
虽然对Counter
实例的操作似乎不可能交错,因为对c
的两个操作都是单个的简单语句。然而,即使简单的语句也可以被虚拟机转换为多个步骤。我们不会讨论虚拟机执行的具体步骤,知道单个表达式c++
可以分解为三个步骤就足够了:
c
的当前值。c
。表达式c--
可以以相同的方式分解,只是第二步是减少而不是增加。
假设线程A在大约同一时间调用increment
,线程B调用decrement
。如果c
的初始值为0
,它们交错的操作可能按照以下顺序进行:
线程A的结果被覆盖,被线程B重写。这个特定的交错只是一种可能性。在不同的情况下,可能是线程B的结果被丢失,或者根本没有错误。由于它们是不可预测的,线程干扰错误可能很难检测和修复。