在Windows中具有竞争条件的java程序,但不在Ubuntu中
在一项旨在强调比赛条件的作业中,我们得到了以下代码
public class IncreaseDecrease {
public static int IntegerVariable = 0;
public static final int NUM_ITER = 5000000;
public static void main(String[] args) throws Exception {
Increase inc;
Decrease dec;
while (true) {
inc = new Increase();
dec = new Decrease();
inc.start();
dec.start();
inc.join();
dec.join();
System.out.println(IntegerVariable);
IntegerVariable = 0;
Thread.sleep(750);
}
}
}
class Increase extends Thread {
@Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.IntegerVariable++;
}
}
}
class Decrease extends Thread {
@Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.IntegerVariable--;
}
}
}
如果每个线程可以在另一个线程读取值之前更新该值,则该代码将打印0,但由于竞争条件的原因,这不会发生,它可以打印-5000000和5000000之间的任何值。
我在windows和repl上运行了该代码。它给出了预期的输出:
-310951
-1918567
-3374495
-3219135
-2286639
-3221055
-3794319
-2442047
-2776415
-3617391
但在Ubuntu上,当我运行它时,它每次都给出0
我的问题是,为什么会发生这种情况?Ubuntu是以不同的方式管理线程,还是只是我电脑的一个特例
编辑: 在将增量放入另一种方法并向其添加一个操作之后,我观察了竞争条件。以下是最终代码:
public class IncreaseDecrease {
public static int IntegerVariable = 0;
public static final int NUM_ITER = 5000000;
public static void main(String[] args) throws Exception {
Increase inc;
Decrease dec;
while (true) {
inc = new Increase();
dec = new Decrease();
inc.start();
dec.start();
inc.join();
dec.join();
System.out.println(IntegerVariable);
IntegerVariable = 0;
Thread.sleep(750);
}
}
public static void increment ()
{
IntegerVariable++;
double a = Math.pow(3, 7);
}
public static void decrement()
{
IntegerVariable--;
double a = Math.pow(3, 7);
}
}
class Increase extends Thread {
@Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.increment();
}
}
}
class Decrease extends Thread {
@Override
public void run() {
for (int i = 0; i < IncreaseDecrease.NUM_ITER; i++) {
IncreaseDecrease.decrement();
}
}
}
# 1 楼答案
关于Java中的线程,有一个常见的误解,即它们真正有效地均匀地交织处理。事实并非如此,不同系统上的不同JVM的工作方式也不同
这一切都源于JVM决定切换线程。JVM可能会在遇到
Thread.sleep()
或synchronized
或lock
等阻塞方法时切换线程,但通常情况下,如果线程没有执行任何涉及阻塞等的操作,它会让线程运行你的循环在不间断地递增和递减一个值。如果在循环中添加
Thread.sleep(0)
调用,您可能会看到不同,因为您为JVM提供了更多的机会来切换线程# 2 楼答案
我猜情况也可能如此
你试过让你的积分变量不稳定吗?这将防止可能发生的一些编译器优化