首页 > 试题广场 >

假设 a 是一个由线程 1 和线程 2 共享的初始值为 0

[单选题]

假设 a 是一个由线程 1 和线程 2 共享的初始值为 0 的全局变量,则线程 1 和线程 2 同时执行下面的代码,最终 a 的结果不可能是()

boolean isOdd = false;
for(int i=1;i<=2;++i){
    if(i%2==1)isOdd = true;
    else isOdd = false;
    a+=i*(isOdd?1:-1);
}
  • -1
  • -2
  • 0
  • 1
两个线程都有+1 ,-2的操作,但是关键是在保存a的值上,ThreadA对a+1,ThreadB也对a+1,ThreadB保存结果,此时a结果为1。虽然ThreadA对a+1但是并没有保存a,所以ThreadA保存a的值为1。
可以注意到虽然两个线程都进行了+1的操作,但是结果是错的。正是因为ThreadA将ThreadB的结果给覆盖了,而不是不执行+1。
知道这个道理之后就好办了
ThreadA的+1和-2操作都可以覆盖ThreadB的+1,-2。
一共有以下几种情况(可能不全):
蓝色框代表不会保存结果,因为黄色框数字将蓝色框数字覆盖了


编辑于 2023-09-22 18:54:55 回复(0)
更多回答
易知:每个线程对a 均做了两次读写操作,分别是 “ +1 ” 和 “ -2 ”
而题目问了是最终a 的结果,所以 a 的结果取决于各自线程对 a 的先后读写的顺序
结论:a的可能取值为-1、0、-2
如图:
发表于 2017-07-01 12:46:01 回复(51)
不管怎样线程对a的操作就是+1后-2
1.线程1执行完再线程2执行,1-2+1-2=-2
2.线程1和2同时+1,再-2不同时,1-2-2=-3
3.线程1和2不同时+1,同时-2,1+1-2=0
4.线程1和2既同时+1又同时-2,1-2=-1
没有结果为1的情况
发表于 2019-06-11 20:02:33 回复(29)
傻了啊,居然没有看到最不可能
发表于 2022-03-08 14:43:17 回复(0)
出题水平太烂
发表于 2017-05-25 21:08:55 回复(0)
假设两线程为A、B,设有3种情况:
1.AB不并发:此时相当于两个方法顺序执行。A执行完后a=-1,B使用-1作为a的初值,B执行完后a=-2
2.AB完全并发:此时读写冲突,相当于只有一个线程对a的读写最终生效。相同于方法只执行了一次。此时a=-1
3.AB部分并发:假设A先进行第一次读写,得到a=1;之后A的读写被B覆盖了。B使用用1作为a的初值,B执行完后a=0

发表于 2017-08-07 12:18:22 回复(7)
首先,每个线程对a做的操作都是+1或者-2
其次,线程对a做的操作有可见不可见的问题.
1. 如果线程A 做了+1,-2,结果是-1,此时如果该结果对于线程B 可见,那么再执行+1,-2,结果是-2;
2. 如果线程A做了+1,-2,结果是-1,但是该结果对线程B并没有见到,那么线程B 最后依然以a==0开始计算,结果是0+1-2=-1,之前线程A 的结果也是-1,此时无论A和B谁的计算结果被最后刷新到公共内存,最后a的值都是-1;
3. 如果线程A做了+1,该结果立即被B看到,B开始进行+1,-2,结果是0,如果该结果被刷新到内存的时机晚于线程A的计算结果,那么结果就是0.
========
对于结果为1的情况,找不到一种执行顺序.

每个线程都有自己的内存区域,线程计算结果刷新到主存的时机也是要考虑的,具体可以了解volatile关键字.
编辑于 2017-08-21 12:12:26 回复(13)
发表于 2019-04-20 15:55:29 回复(6)
因为+=不是原子操作,所以导致多线程操作a的结果有多种,大概画了下图(其实下图不是所有情况,只是列举了其中几种,还有挺多种情况没画出来, 但是结果还是0,-1,-2,-3)

编辑于 2018-07-18 23:16:06 回复(5)
C;
(i%2?1:-1)的值:i为偶数为-1,i为奇数为1;
因为for循环中是++i,所以i的值取了2和3;
i=2时,a的值减2,i=3时,a的值加3,由于2个线程同时进行,不知道会先执行哪个,也不知道会执行到哪一步,但对a的值来说,减2和加3的两个操作各能进行2次,所以a的取值可能为:
a=-2;a=-2+3=1;a=-2-2+3=-1;
对两个-2和两个3,无论怎么操作都得不到0,所以选C

编辑于 2017-06-03 11:53:49 回复(25)
俩个线程执行四次操作。1.a + 1 ; 2.a - 2; 3.a + 1 ; 4.a - 2 ;缓存不一致的情况会导致什么呢,会导致覆盖已经进行过的运算,但是只有一次的运算是覆盖不了的。所以整个运算 a + 1 和 a - 2 必须执行一次。
剩下的运算随意组合执行。结果有:
1 : a + 1 - 2 +1 -2 = -2
2 : a + 1 - 2 + 1 = 0
3: a + 1 - 2 - 2 = -3
4 : a + 1 - 2 = -1
这样就得出了结论了,这是我的一个猜想,请大家拍砖


发表于 2019-04-08 16:17:37 回复(3)
0的情况比较难得到,-1,-2的结构比较容易得出,所以不会出现的结果是1
发表于 2017-06-18 10:34:49 回复(3)
a1 = 0(A线程与B线程全局共享的数值 )

A线程+B线程(多核CPU并行)
i = 1   a2=  0  (a1)+1*1        a2 = 1
i=  2   a3=  1(a2)+2* -1      a3 = -1
结果:-1

A线程+B线程(单核CPU ,i=1串行,i=2并行)
i = 1   a2=  0 (a1)+ 1*1        a2 = 1
i = 1   a3=  1 (a2)+ 1*1        a3 = 2
i=  2   a4=  2 (a3)+2* -1       a4 = 0
结果:0

A线程+B线程(单核CPU ,i=1并行,i=2串行)
i = 1   a2=  0  (a1)+ 1*1       a2 = 1
i=  2   a3=  1  (a2)+2* -1      a3 = -1
i=  2   a4= -1 (a3) +2* -1      a4 = -3
结果:-3

A线程+B线程(单核CPU ,i=1串行,i=2串行)
i = 1   a2=  0 + 1*1        a2 = 1
i = 1   a3=  1 + 1*1        a3 = 2
i=  2   a4=  2 +2* -1      a4  = 0
i=  2   a5=  0 +2* -1      a5  = -2
结果:-2

排除后:a的结果不可能是1
发表于 2021-07-02 21:33:08 回复(1)
这一题没考虑好,以为两个线程都会执行完毕,原来存在读写冲突时发生覆盖的情况!!!就是一个线程执行完一个循环后,另一个线程抢占后,之前线程后面的循环有可能就不会执行到了。
发表于 2017-08-19 19:57:14 回复(4)
发表于 2021-09-01 14:54:37 回复(1)
出这题的是xx,上面写答案的也都是xx,真当自己是Doug Lea?关于多线程,我们不是并发大牛的所要做的就是按照java给出的规则去写出在使用上线程安全的代码,出了问题是看违反了什么规则。而不是像这样一头雾水地去找某种结果是怎样出现的。想要看懂上面那几个答案在说什么的,去看深入理解java虚拟机第十二章就行了,看完你也能装模作样的分析一下。
发表于 2019-01-19 01:59:28 回复(1)
对读写冲突有疑问的可以看下我的理解
借用@Likwind的图
理解读写冲突的关键是要理解局部变量和共享变量。
当线程对一个共享变量进行操作时,先创建一个线程内变量保存共享变量的值,操作完成后再将这个线程内变量的值写回共享变量。
以情形1为例.
读a1,Thread1、2创线程内变量tempA=tempB=a=0
写a1,进过运算,tempA=tempB=1,Thread1、2又分别将tempA、tempB写回a,a=tempA=1,a=tempB=1.结果a=1.
下面类似
发表于 2017-08-20 09:18:36 回复(0)
不管怎样线程对a的操作就是+1后-2 1.线程1执行完再线程2执行,1-2+1-2=-2 2.线程1和2同时+1,再-2不同时,1-2-2=-3 3.线程1和2不同时+1,同时-2,1+1-2=0 4.线程1和2既同时+1又同时-2,1-2=-1 没有结果为1的情况
发表于 2021-10-02 00:05:11 回复(0)
其实把一楼那张图的矩形看成时间点,而不是时间段,线程二在线程一的时间点之间的空隙开始自己的线程,这样就好看好理解了。所以一共有四种情况:-1,-3,0,-2。欢迎讨论。
编辑于 2019-01-19 15:17:10 回复(1)

首先我们要明确一点的是,只有变量a是共享数据,变量i和isOdd不是共享变量,所以,每个线程对a均做了两次读写操作,分别是 “+1” 和 “-2”。

因为“+=”不是原子操作,在执行时会变成多条指令,所以会出现并发问题。这里可以举个简单的例子,a+=1可以理解成a=a+1。如果线程1读取变量a的值为0,此时线程2抢占了CPU,也读取到变量a的值为0,并进行了+1操作,将a=1写入到变量a中。线程2该操作执行完成后,CPU被线程1抢占,会继续进行后续操作,此时线程1使用原先读取到的变量a的值0进行+1操作,然后将a=1写入到变量a,这里相当于是覆盖了之前线程2写入的变量a的值。从结果上来看,线程1和线程2都执行了+1操作,但a的值却是1,看起来像线程1和线程2同时执行的情况。

理解上面这一情况后,就可以很容易进行判断了:

    ◆ 线程1执行完再线程2执行,1-2+1-2=-2

    ◆ 线程1和2同时+1,再-2不同时,1-2-2=-3

    ◆ 线程1和2不同时+1,同时-2,1+1-2=0

    ◆ 线程1和2既同时+1又同时-2,1-2=-1

所以,不可能出现结果为1的情况,答案选D。

发表于 2022-08-04 10:48:28 回复(0)
多线程并发可能出现指令交错的现象。
发表于 2022-01-26 16:07:23 回复(0)