我一直在研究java中的同步并尝试运行以下程序
public class Example {
public static void main(String[] args) {
Counter counterA = new Counter();
Counter counterB = new Counter();
Thread threadA = new CounterThread(counterA);
Thread threadB = new CounterThread(counterB);
threadA.start();
threadB.start();
}
}
class CounterThread extends Thread {
protected Counter counter = null;
public CounterThread(Counter counter){
this.counter = counter;
}
public void run() {
for(int i=0; i<2; i++){
counter.add(i);
}
}
}
class Counter {
long count = 0;
public synchronized void add(long value){
this.count += value;
System.out.println(this.count);
}
}
当我运行上面的代码时,当我运行Example类作为java应用程序或调试Example类时,它给出了相同的输出
0
1
0
1
但是如果我将计数器类的count变量的访问修饰符修改为静态,如下所述:
static long count = 0;
现在如果尝试运行Example类,我将输出作为
0
1
0
2
但是当我调试Example类时,我得到输出为
0
1
1
2
任何人都可以帮我理解其中的区别。 在此先感谢并道歉,因为我是多线程概念的新手
答案 0 :(得分:0)
每个实例都有自己的实例变量副本,但它们共享静态变量。因为你有两个类的实例和两个在这些实例上运行的线程:
Counter counterA = new Counter();
Counter counterB = new Counter();
Thread threadA = new CounterThread(counterA);
Thread threadB = new CounterThread(counterB);
所以效果很明显。当count
是非静态的时,两个线程不会影响两个不同对象的count
。但是当count
是静态的时,两个线程处理由两个实例共享的同一个变量。
当你有两个独立的线程在运行时,执行顺序是动态的,这取决于Thread Scheduler如何选择要执行的线程。使用调试器不一定会影响它,事实上,正常执行程序可能会看到不同的结果。
答案 1 :(得分:0)
synchronized
仅保护您免受同时在同一实例上输入方法的两个来电者。所以它基本上不会影响你的例子。
非静态情况:每个线程都在更新自己的Counter.count
实例。你可以得到0-1-0-1或0-0-1-1(更不可能)作为输出。
静态情况:每个线程都通过两个不同的 Counter.count
实例更新相同的Counter
。您可以获得0-0-1-2,0-1-1-2和0-1-0-2。
为什么选择最后一个?您只影响静态Coutner.count
实例,而不影响静态Counter
实例。因此,两个线程都可以在Counter.add
内,并且一个线程可能已经加载0用于输出它,但是其他线程然后更新它并输出1,然后只有第一个线程输出其0。
你得到的0-0-1-2,0-1-1-2或0-1-0-2中的哪一个根本没有定义,并且 NOT 依赖于debug&amp;发布模式。然而,在调试和接收中接收不同的结果是很常见的。由于编译器生成的汇编代码不同而导致发布模式。