4 回答
TA贡献1841条经验 获得超3个赞
我声称可能的最小值是 2。
关键是 的非原子性num++
,即它是一个读和一个写,中间可能还有其他操作。
调用线程 T1..T5:
T1读0,T2读0;
T1写1,然后读写3次。
然后T2写1;
那么T1读为1;
然后T2-5完成他们所有的工作
最后,T1 写入 2。
(注意:结果 2 不依赖于线程数或迭代次数,前提是每个线程至少有 2 个。)
但诚实的答案是:这真的不重要。存在数据竞争,如JLS 17.4.5中所定义:
当程序包含两个未排序的冲突访问时(第 17.4.1 节 [“如果至少其中一个访问是写入,则对同一变量的两次访问(读取或写入)被认为是冲突的。”])通过事前发生的关系,据说它包含 数据竞争。
(线程中的操作之间不存在happens-before关系)
所以你不能有效地依赖它所做的任何事情。这只是不正确的代码。
(此外,我知道这个问题的答案并不是因为调试多线程代码的一些来之不易的战斗,或者是深入的技术阅读:我知道这一点是因为我之前在其他地方读过这个答案。这是一个客厅技巧,仅此而已,所以询问最小值不是一个很好的面试问题)。
TA贡献1777条经验 获得超3个赞
您的线程正在更新一个非易失性变量,这意味着它不能保证每个线程都会看到 的更新值num
。让我们考虑以下线程的执行流程:
Thread 1: 0->1->2 (2 iteration left) Thread 2: 0->1->2->3 (1 iteration left) Thread 3: 0->1->2->3 (1 iteration left) Thread 4: 0->1->2->3 (1 iteration left) Thread 5: 0->1->2->3 (1 iteration left)
此时,线程 1 将 num 的值刷新到内存,线程 2,3,4,5 决定再次从内存中2
读取 num (出于任何原因)。num
现在:
Thread 1: 2->3->4 (completed 2 iteration) Thread 2: 2->3 (completed 1 iteration) Thread 3: 2->3 (completed 1 iteration) Thread 4: 2->3 (completed 1 iteration) Thread 5: 2->3 (completed 1 iteration)
线程 1 将值刷新4
到内存,之后 Theard 2,3,4.. 将值刷新到内存,显示该数字的当前值将3
代替5
TA贡献1806条经验 获得超5个赞
在我看来,由于缺乏原子操作,达到 25 是完全不可能的。
所有线程几乎同时启动,因此每个线程都会看到与第一次迭代ThreadTest.num
一样的值。0
由于有 5 个线程并行访问同一变量,因此在第三次迭代时,线程可能会看到ThreadTest.num
值仍然为1
or 2
,并且会错误地增加到2
or 3
。
根据硬件的不同,最终值会更低或更高,最快的可能具有最低的值,最慢的可能具有较高的值。但我的主张是最大值不能达到 25。
编辑 (2019-10-07)
我在自己的机器(Core i5 HQ)上进行了测试,确实最终结果25
几乎每次都达到了。为了更好地理解,我在循环中使用更大的数字进行了测试for
:
for (int i = 0; i < 10000; i++) { num++; }
现在,大多数时候,最终结果都在20000到30000之间,与50000相差甚远。
TA贡献1854条经验 获得超8个赞
好吧,我的答案是 Max 25,Min 0,因为你所有的操作都是递增的,并且你将其初始化为 0.. 我认为静态非易失性 int 被扔在那里让你进入这些关于种族的想法条件,但是其中是否有任何东西可以在任何情况下减少数字?
编辑:就其价值而言,这将是一种典型的干扰,他们可能希望您能够在现实世界中克服这种干扰,证明这种“欺骗”的合理性,有很多转移注意力的事情!
添加回答
举报