带和不带静态变量的Java同步

时间:2015-07-08 22:10:24

标签: java multithreading static

我一直在研究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

任何人都可以帮我理解其中的区别。 在此先感谢并道歉,因为我是多线程概念的新手

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;发布模式。然而,在调试和接收中接收不同的结果是很常见的。由于编译器生成的汇编代码不同而导致发布模式。