Java synchronized 類鎖和對象鎖的區別

synchronized 加到 static 方法前面是給class 加鎖,即類鎖;而synchronized 加到非靜態方法前面是給對象上鎖。這兩者的區別我用代碼來演示下:

1.類鎖和對象鎖是兩把不同的鎖,多線程執行兩個不同鎖的方法時是異步的

加鎖的類(下面幾個此類不變)

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");

    }
}

多線程如下

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函數如下

public static void main(String[] args) {
         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
name = C, begain
name = C, end
name = A, end
name = B, begain
name = B, end

doLongTimeTaskA()和 doLongTimeTaskB()互斥,與doLongTimeTaskC()不互斥,類鎖和對象鎖是兩類不同的鎖

2,對象鎖對同一個實列對象起作用,類鎖對該類的所有實列對象起作用

加鎖類不變,用上面的

多線程更改如下

 

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函數如下

public static void main(String[] args) {
    
      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
name = B, begain
name = A, end
name = B, end

對象鎖鎖的對象不一樣,分別是mTaska , mTaskb,所以線程A和線程B調用 doLongTimeTaskC 是異步執行的。

然後我們main函數不變,依舊是對兩個實列而言 ,更改多線程的class走類鎖,執行doLongTimeTaskA()或者doLongTimeTaskB()

更改後的多線程類如下

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();
    }
}

 

結果如下

name = A, begain
name = A, end
name = B, begain
name = B, end

可以看出 在線程A執行完doLongTimeTaskA方法後,線程B纔會獲得該類鎖接着去執行doLongTimeTaskA。也就是說,類鎖對所有的該類對象都能起作用。

 

 

結論:

1. 如果多線程同時訪問同一類的 類鎖(synchronized 修飾的靜態方法)以及對象鎖(synchronized 修飾的非靜態方法)這兩個方法執行是異步的,原因:類鎖和對象鎖是2種不同的鎖。 
2. 類鎖對該類的所有對象都能起作用,而對象鎖只對同一個實例對象起作用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章