任何人都可以在后台发生什么

时间:2015-02-20 08:10:50

标签: java thread-synchronization

package workouts;

public class synchro {

    private int count = 0;

    public void counting() {

        Thread T1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {

                    count++;
                }
            }
        });

        Thread T2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {

                    count++;
                }
            }
        });

        T1.start();
        T2.start();

        try {
            T1.join();
            T2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("counting =" + count);
    }

    public static void main(String[] args) {

        synchro sync = new synchro();

        sync.counting();
    }
}

但是当引入一个synchronized方法并在下面运行方法中调用它时...输出是20000,如果你运行它多少次..有人解释上面和下面代码之间的区别

public class synchro {

    private int count = 0;

    public synchronized void dosinglethread(){
        count++;
    }

    public void counting() {

        Thread T1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    dosinglethread();
                }
            }
        });

        Thread T2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {

                    dosinglethread();
                }
            }
        });

        T1.start();
        T2.start();

        try {
            T1.join();
            T2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("counting =" + count);
    }

    public static void main(String[] args) {
        synchro sync = new synchro();

        sync.counting();
    }
}

1 个答案:

答案 0 :(得分:1)

当你说count++时,会发生三件事:

  1. VM检索count的当前值
  2. VM将值递增1
  3. 新值将重新投入count
  4. T1和T2完全有可能获得count的值,然后单独递增,然后返回结果,如下所示:

    Timeslot    T1                    T2
    1           count = 3             ----
    2           ----                 count = 3
    3           3 + 1 = 4            ----
    4           ----                 3 + 1 = 4
    5           store 4 in count     ----
    6           ----                 store 4 in count
    

    现在,count++已被调用两次,但该值仅增加了一倍。要防止这种情况,您必须使增量原子。原子意味着执行整个操作序列,或者不执行任何操作。简单地说,如果两个语句synchronized在同一个Object上,则它们不会交错。

    在您的第二段代码中,dosinglethread()被声明为synchronized。这相当于:

    public void dosinglethread() {
        synchronized (this) {
            count++;
        }
    }
    

    这意味着当其中一个线程开始执行它时,它们会在synchro实例上获取 lock 。当第二个线程也试图执行该方法时,它会看到另一个线程已经拥有this上的锁,所以它必须等待。当第一个线程完成该方法时,它将释放锁定,然后另一个线程可以接受它。

    那么为什么volatile不起作用? volatile变量不会导致线程等待它们可用。相反,当countvolatile且您致电count++时,会发生以下情况:(代码改编自Javamex's Tutorial

    int temp;
    synchronized (count) {
      temp = count;
    }
    temp = temp + 1;
    synchronized (count) {
      count = temp;
    }
    

    请注意,此代码仅供参考:synchronized不能用于基元。

    很明显,线程可能仍在temp = temp + 1暂停,给出了与不进行任何同步时相同的问题。

    有关详情,请查看the tutorial I mentioned.