java中synchronized鎖定物件問題

小鞅發表於2016-03-14

java中synchronized鎖定物件問題

關於synchronized關鍵字介紹的部落格有很多,也很詳細,但是還是有很多問題讓我很迷惑,比如synchronized鎖定物件到底該怎麼設定的問題,通過檢視資料和理解終於了,向大家分享一下:
迷惑1:為什麼一個物件被鎖定以後別的執行緒還可以訪問訪問該物件的其他非synchronized塊的程式碼?
迷惑2:為什麼被上鎖物件的其他synchronized塊只能被當前擁有鎖的執行緒執行?

class Counter implements Runnable {
    private int count;

    public Counter() {
        count = 0;
    }

    public void countAdd() {
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ":" + (count++));
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 非synchronized程式碼塊,未對count進行讀寫操作,所以可以不用synchronized
    public void printCount() {
        for (int i = 0; i < 5; i++) {
            try {
                System.out.println(Thread.currentThread().getName() + " count:" + count);
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void run() {
        String threadName = Thread.currentThread().getName();
        if (threadName.equals("A")) {
            countAdd();
        } else if (threadName.equals("B")) {
            printCount();
        }
    }
}

呼叫程式碼:

Counter counter = new Counter();
Thread thread1 = new Thread(counter, "A");
Thread thread2 = new Thread(counter, "B");
thread1.start();
thread2.start();

結果如下:

    A:0
    B count:1
    A:1
    B count:2
    A:2
    B count:3
    A:3
    B count:4
    A:4
    B count:5

上面程式碼中countAdd是一個synchronized的,printCount是非synchronized的。從上面的結果中可以看出一個執行緒訪問一個物件的synchronized程式碼塊時,別的執行緒可以訪問該物件的非synchronized程式碼塊而不受阻塞。

解釋:
synchronized的引數代表被上鎖的物件,當編譯器遇到synchronized關鍵字的時候,就會在class檔案中生成monitorenter指令。當程式執行遇到monitorenter指令的時候,會預先檢查synchronized引數中的物件是否被別的執行緒持有(即該物件是否被上鎖),所以同一個物件如果多個synchronized塊只能被一個執行緒當前擁有同步塊的執行緒隨意執行,而別的執行緒是不能執行該被鎖物件的任何synchronized塊,但是可以執行其他非同步塊方法塊程式碼,因為執行其他的方法不會掃面當前物件是否被上鎖,也就是其他非synchronized塊沒有monitorenter這個指令,所以別的執行緒可以訪問上鎖物件的非synchronized程式碼。

關於synchronized關鍵字詳細介紹請參考:
http://blog.csdn.net/luoweifu/article/details/46613015

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

相關文章