有人可以解释这段代码中竞争条件的位置。我的讲师设定了它,我还没有完全理解如何发现它们,或者说出为什么会给出结果。
public class SlowRace {
public static void main(String args []) throws Exception {
MyThread.count = 0 ;
MyThread thread1 = new MyThread() ;
thread1.name = "A" ;
MyThread thread2 = new MyThread() ;
thread2.name = "B" ;
thread1.start() ;
thread2.start() ;
thread2.join() ;
thread1.join() ;
System.out.println("MyThread.count = " + MyThread.count) ;
}
}
class MyThread extends Thread {
volatile static int count ;
String name ;
public void run() {
for(int i = 0 ; i < 10 ; i++) {
delay() ;
int x = count ;
System.out.println("Thread " + name + " read " + x) ;
delay() ;
count = x + 1;
System.out.println("Thread " + name + " wrote " + (x + 1)) ;
}
}
static void delay() {
int delay = (int) (1000000000 * Math.random()) ;
for(int i = 0 ; i < delay ; i++) {}
}
}
返回的结果:
Thread A read 0
Thread A wrote 1
Thread B read 0
Thread A read 1
Thread B wrote 1
Thread A wrote 2
Thread B read 2
Thread A read 2
Thread B wrote 3
Thread A wrote 3
Thread B read 3
Thread A read 3
Thread B wrote 4
Thread A wrote 4
Thread B read 4
Thread A read 4
Thread B wrote 5
Thread A wrote 5
Thread B read 5
Thread A read 5
Thread B wrote 6
Thread A wrote 6
Thread B read 6
Thread A read 6
Thread B wrote 7
Thread A wrote 7
Thread B read 7
Thread A read 7
Thread B wrote 8
Thread A wrote 8
Thread B read 8
Thread A read 8
Thread B wrote 9
Thread A wrote 9
Thread B read 9
Thread A read 9
Thread B wrote 10
Thread A wrote 10
Thread B read 10
Thread B wrote 11
MyThread.count = 11
答案 0 :(得分:2)
嘿,伙计们可以解释这段代码中竞争条件的位置,
比赛就在这些界限之间:
int x = count ;
...
count = x + 1;
一个线程获取值,但另一个线程可以获得相同的值,然后第一个线程使用递增的值更新它。那是比赛。
count
的值并将其存储在x
中。 x
是(比方说10)。count
的值并将其存储在x
中。 x
是(比方说10)。x
增加为11
并将其存储回count
。x
的副本增加为11
并将其存储回count
- 这会覆盖线程1的增量。因此,count
不是12,而是其中一个增量将丢失,它将为11。
练习是指出增量不是原子的。实际上delay()
不是必需的。 count++
也会证明这个问题,因为它不是原子的(get / increment / set),并且线程可以在3个操作的中间被中断。
使这段代码复杂化的一件事是System.out.println(...)
是同步的,所以控制台输出会改变程序的时间。
答案 1 :(得分:0)
您告诉编译器将信息存储在内存而不是缓存中。
volatile static int count ;
同时执行此运行的2个线程。
public void run() {
for(int i = 0 ; i < 10 ; i++) {
delay() ;
int x = count ;
System.out.println("Thread " + name + " read " + x) ;
delay() ;
count = x + 1;
System.out.println("Thread " + name + " wrote " + (x + 1)) ;
}
}
想象。
count = 0;
Thread1(int x = count); //x = 0;
Thread1(delay)
Thread2(int x = count); //x = 0;
Thread2(delay)
Thread1(count = x + 1); //count = 1;
Thread2(count = x + 1); //count = 1; //While it has to be 2.
答案 2 :(得分:0)
由于对MyThread类中的静态变量 count 进行了不受保护的更新,因此该逻辑是线程不安全的。
主线程将在启动后加入Thread1和Thread2,并等待它们完成。但是,同时运行具有不幸时序的线程(Thread1,Thread2)可能最终将变量“count”与相同值一起更新。