簡體   English   中英

System.out.println與Java volatile

[英]System.out.println with java volatile

我有一個這樣的例子:

public class MainApp {

    private volatile static int MY_INT = 0;

    public static void main(String[] args) {
        new Thread1().start();
        new Thread2().start();
    }

    static class Thread1 extends Thread {
        @Override
        public void run() {
            while(true) {
                MY_INT++;
                System.out.println("1 : " + MY_INT);
            }
        }
    }

    static class Thread2 extends Thread{
        @Override
        public void run() {
            while(true) {
                MY_INT++;
                System.out.println("2 : " + MY_INT);
            }
        }
    }
}

輸出為:

1 : 1
2 : 2
1 : 3
2 : 4
1 : 5
1 : 7
1 : 8
1 : 9
1 : 10
2 : 6
1 : 11
1 : 13

我不明白為什么在打印1:10后下一行是2:6。 誰能解釋結果? 提前致謝

這里有幾個問題:

  • 線程可能無法並行運行。 它們以時間片運行(默認值:在PC上為15.6毫秒;每秒64滴答,請參閱計時器分辨率(Microsoft) )。 這就是為什么您看不到一個接一個的1:x2:x ,而是幾個接一個的1:x
  • 使用volatile不利於同步。 你需要真正的同步對象,如AtomicIntegersynchronized關鍵字。 因此,您可能會看到跳過的數字(輸出中不是這種情況,但是可能會發生)。 如果要查看唯一的數字,則需要圍繞++println()進行同步
  • 控制台輸出被緩沖和同步,因為您不希望2個println語句在一行上混合輸出

System.out的PrintStream和volatile字段MY_INT是獨立同步的,因此可能發生以下情況:

Thread 1               Thread 2
read MY_INT = 4
write MY_INT = 5
read MY_INT = 5
                       read MY_INT = 5
                       write MY_INT = 6
                       read MY_INT = 6
println 5
read MY_INT = 6
write MY_INT = 7
read MY_INT = 7
println 7

...
                       println 6

也就是說,由於System.out返回的volatile字段和PrintStream是獨立同步的,因此打印可能以非升序順序進行。

也可能發生以下情況:

Thread 1            Thread 2
read MY_INT = 1
                    read MY_INT = 1
write MY_INT = 2
                    write MY_INT = 2
read MY_INT = 2
println 2
                    read MY_INT = 2
                    println 2

因為++ MY_INT實際上被編譯為讀取,計算和寫入。 由於易失性讀取和寫入是單獨的同步操作,因此其他線程可能在兩者之間起作用,並使計數器混亂。

如果要通過單獨的線程打印升序數字,最簡單的方法是:

void run() {
   while (true) {
       synchronized (lock) {
           MY_INT++;
           System.out.println("1 : " + MY_INT);
       }
   }
}

其中lock是所有訪問MY_INT的線程共享的對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM