我试图理解两个线程更新的classMember
的可能值是什么,当我运行程序时输出总是20,但我想理解为什么它发生了什么是mimumum,classMember
public class TestClass {
public int classMember = 0;
private void updateCM() {
for (int i = 0; i < 10; i++) {
classMember++;
}
}
public static void main(String[] args) {
TestClass mainClass = new TestClass();
Thread t1 = new Thread(mainClass::updateCM);
Thread t2 = new Thread(mainClass::updateCM);
t1.start();
t2.start();
while(t1.isAlive() || t2.isAlive()) {}
System.out.println(mainClass.classMember);
}
}
答案 0 :(得分:4)
我认为您需要阅读此Stackoverflow线程
Make multiple threads use and change the same variable
由于您在同一实例中更新相同的变量,因此可能存在同步问题。此案例的相应关键字为volatile
。但是,即使你将volatile设置为你的变量,这也是不够的,因为++实际上不是单一的,而是三个操作,这使得它不是原子的。
我也会引用这段文字
虽然这会处理内存同步,但它并不一定能保护您免受竞争条件的影响。同样重要的是要意识到++实际上是3个操作:获取当前值,增加它并再次存储它。如果多个线程试图这样做,则存在线程竞争条件,这可能导致错过++操作。 在这种情况下,您应该使用包含volatile int字段的AtomicInteger类。它为您提供了incrementAndGet()等方法,它们以线程安全的方式完成递增该字段的工作。
答案 1 :(得分:1)
增量不是原子操作,因此每次运行程序时结果都可能不同。在这种情况下,我认为,第一个线程只是在处理器给第二个线程执行它的操作之前完成递增变量的值。但是,例如,如果你开始两个线程,第一个将减少变量的值十亿次,而第二个线程则相反 - 增加十亿次,你会得到一些非常意外的东西(当然,如果你是不会使这个变量线程安全。)
答案 2 :(得分:1)
10到20之间的所有值(包括10和20)都是可能的结果。
在最坏的情况下,一个线程的每个增量(不是原子的,由读内存,增加,写内存组成)都与其他线程交织。
可能的交错(为了简洁而省略了&#39;增加&#39;操作):
Thread1 Thread2
Read 0
Read 0
Write 1
Write 1
Read 1
Read 1
Write 2
Write 2
Read 2
Read 2
Write 3
Write 3
Read 3
Read 3
Write 4
Write 4
Read 4
Read 4
Write 5
Read 5
Write 5
Read 5
Write 6
Read 6
Write 6
Read 6
Write 7
Read 7
Write 7
Read 7
Write 8
Read 8
Write 8
Read 8
Write 9
Read 9
Write 9
Read 9
Write 10
Write 10
另一种可能的交错:
Thread1 Thread2
Read 0
Read 0
Write 1
Read 1
Write 2
Read 2
Write 3
Read 3
Write 4
Read 4
Write 5
Read 5
Write 6
Read 6
Write 7
Read 7
Write 8
Read 8
Write 9
Read 9
Write 10
Write 1
Read 1
Write 2
Read 2
Write 3
Read 3
Write 4
Read 4
Write 5
Read 5
Write 6
Read 6
Write 7
Read 7
Write 8
Read 8
Write 9
Read 9
Write 10
答案 3 :(得分:0)
最小值是初始化值,即0。
关于最大值,虽然您创建了两个Thread实例,但两个实例都使用相同的TestClass实例,因此,将classMember变量递增2次* 10次,得到的值为20.
答案 4 :(得分:0)
很可能是因为运气不好,或者“样本太少”。如果你愿意的话。 JIT编译器还没有完成它的工作,因此无论运行什么都可能不是最佳的并且使用简单的技术。
如果您将最大值从10更改为1,000,000,那么将看到总数确实没有加起来,并且会在不同的运行中产生不同的结果。
答案 5 :(得分:-2)
TestClass mainClass = new TestClass();
现在该值设置为0.
t1.start(); // 0-10
t2.start(); /10- 20
最后,classMember
为20。