一个程序运行多个线程本身没有问题
问题出在多个线程访问共享资源
一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区
下面应用操作r
变量,可以看作临界区
两个线程一个加一个减带来的问题
public void test1() throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
r++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
r--;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(r);
}
问题出现的原因:
例如对于 i++
而言(i 为静态变量),实际会产生如下的 JVM 字节码
指令:
而 Java 的内存模型如下,完成静态变量的自增,自减需要在主存和工作内存中进行数据交换
:
因此,如果线程2自减完,但是还没有写入
,然后线程1操作完,线程2在写入
,就会出现这样的问题。
多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件
为了避免临界区的竞态条件发生,有多种手段可以达到目的。