面試官:你能談談Java中 synchronized 對象鎖和類鎖的區別

點擊上方Java學習指南關注公衆號
java

天天閱讀Java乾貨文章web


synchronized 加到 static 方法前面是給class 加鎖,即類鎖;而synchronized 加到非靜態方法前面是給對象上鎖。面試

這二者的區別我用代碼來演示下微信

對象鎖和類鎖是不一樣的鎖,因此多個線程同時執行這2個不一樣鎖的方法時,是異步的。

在Task2 中定義三個方法 doLongTimeTaskA和doLongTimeTaskB是類鎖,而doLongTimeTaskC是對象鎖。多線程

public class Task2 {

    public synchronized static void doLongTimeTaskA() {
        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");
    }

    public synchronized static void doLongTimeTaskB() {
        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");
    }

    public synchronized void doLongTimeTaskC() {

        System.out.println("name = " + Thread.currentThread().getName() + ", begain");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("name = " + Thread.currentThread().getName() + ", end");

    }

三個線程的代碼以下:app

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskA();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskB();
    }
}

class ThreadC extends Thread{

    private Task2 mTask2;

    public ThreadC(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

main函數中執行代碼以下:異步

        Task2 mTask2 = new Task2();
        ThreadA ta = new ThreadA(mTask2);
        ThreadB tb = new ThreadB(mTask2);
        ThreadC tc = new ThreadC(mTask2);

        ta.setName("A");
        tb.setName("B");
        tc.setName("C");

        ta.start();
        tb.start();
        tc.start();

執行的結果以下:編輯器

name = A, begain, time = 1487311199783
name = C, begain, time = 1487311199783
name = C, end, time = 1487311200784
name = A, end, time = 1487311200784
name = B, begain, time = 1487311200784
name = B, end, time = 1487311201784

能夠看出因爲 doLongTimeTaskA和doLongTimeTaskB都是類鎖,即同一個鎖,因此 A和B是按順序執行,即同步的。而C是對象鎖,和A/B不是同一種鎖,因此C和A、B是 異步執行的。(A、B、C代指上面的3中方法)。函數

更多面試題,歡迎關注公衆號 Java面試題精選學習

咱們知道對象鎖要想保持同步執行,那麼鎖住的必須是同一個對象。下面就修改下上面的來證實:

Task2.java不變,修改ThreadA 和 ThreadB 以下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        mTask2.doLongTimeTaskC();
    }
}

main方法以下:

 Task2 mTaska = new Task2();
 Task2 mTaskb = new Task2();
 ThreadA ta = new ThreadA(mTaska );
 ThreadB tb = new ThreadB(mTaskb );


 ta.setName("A");
 tb.setName("B");

 ta.start();
 tb.start();

結果以下:

name = A, begain, time = 1487311905775
name = B, begain, time = 1487311905775
name = B, end, time = 1487311906775
name = A, end, time = 1487311906775

從結果看來,對象鎖鎖的對象不同,分別是mTaska , mTaskb,因此線程A和線程B調用 doLongTimeTaskC 是異步執行的。

可是,類鎖能夠對類的全部對象的實例起做用。只需修改ThradA 和 ThreadB,main 方法不作改變,修改以下:

class ThreadA extends Thread{

    private Task2 mTask2;

    public ThreadA(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
        //mTask2.doLongTimeTaskC();
        mTask2.doLongTimeTaskA();
    }
}

class ThreadB extends Thread{

    private Task2 mTask2;

    public ThreadB(Task2 tk){
        mTask2 = tk;
    }

    public void run() {
       //mTask2.doLongTimeTaskC();
        mTask2.doLongTimeTaskA();
    }
}

結果以下:

name = A, begain, time = 1487312239674
name = A, end, time = 1487312240674
name = B, begain, time = 1487312240674
name = B, end, time = 1487312241674

能夠看出 在線程A執行完doLongTimeTaskA方法後,線程B纔會得到該類鎖接着去執行doLongTimeTaskA。也就是說,類鎖對全部的該類對象都能起做用。

Java學習指南:一個只分享Java乾貨的公衆號。

總結:

  1. 若是多線程同時訪問同一類的 類鎖(synchronized 修飾的靜態方法)以及對象鎖(synchronized 修飾的非靜態方法)這兩個方法執行是異步的,緣由:類鎖和對象鎖是兩種不一樣的鎖。
  2. 類鎖對該類的全部對象都能起做用,而對象鎖不能。

做者:小豬快跑22
blog.csdn.net/zhujiangtaotaise/article/details/55509939


END



若是文章對您有幫助,請您分享、點贊、在看,一波三連支持一下做者,很是感謝!

本文分享自微信公衆號 - Java學習指南(gh_85b94beaede2)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索