1. 程式人生 > >16、靜態同步synchronized方法與synchronized(class)程式碼塊

16、靜態同步synchronized方法與synchronized(class)程式碼塊

靜態同步synchronized方法

package com.demo19;

public class MyObject {
    synchronized public static void a(){
        try {
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void b(){
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
    }
}
package com.demo19;

public class ThreadA extends Thread {
    @Override
    public void run() {
        MyObject.a();
    }
}
package com.demo19;

public class ThreadB extends Thread {
    @Override
    public void run() {
        MyObject.b();
    }
}
package com.demo19;

public class run {
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        ThreadB threadB = new ThreadB();
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

執行結果:

執行緒:A 開始時間:1544844475598
執行緒:A 結束時間:1544844478598
執行緒:B 開始時間:1544844478598
執行緒:B 結束時間:1544844478598

看上去跟之前使用synchronized同步非靜態方法的效果沒什麼區別,但本質上卻是有區別的。synchronized同步靜態方法,加在class上;synchronized同步非靜態方法,是給物件上鎖。

為了驗證不是同一個鎖,繼續進行實驗。

package com.demo19;

public class MyObject {
    synchronized public static void a(){
        try {
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void b(){
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
    }
    synchronized public void c(){
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
    }
}
package com.demo19;

public class ThreadA extends Thread {
    private MyObject myObject;

    public ThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        MyObject.a();
    }
}
package com.demo19;

public class ThreadB extends Thread {
    private MyObject myObject;

    public ThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        MyObject.b();
    }
}
package com.demo19;

public class ThreadC extends Thread {
    private MyObject myObject;

    public ThreadC(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run(){
        myObject.c();
    }
}
package com.demo19;

public class run {
    public static void main(String[] args) {
        MyObject myObject = new MyObject();
        ThreadA threadA = new ThreadA(myObject);
        ThreadB threadB = new ThreadB(myObject);
        ThreadC threadC = new ThreadC(myObject);
        threadA.setName("A");
        threadB.setName("B");
        threadC.setName("C");
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

執行結果:

執行緒:A 開始時間:1544845870678
執行緒:C 開始時間:1544845870679
執行緒:C 結束時間:1544845870679
執行緒:A 結束時間:1544845873678
執行緒:B 開始時間:1544845873678
執行緒:B 結束時間:1544845873678

很明顯 非同步,原因是持有不同的鎖。一個是物件鎖,一個是class鎖。class鎖可以對類的所有例項物件起作用!

下面對該結論進行實驗:

package com.demo19;

public class MyObject {
    synchronized public static void a(){
        try {
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void b(){
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
        System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
    }
}
package com.demo19;

public class ThreadA extends Thread {
    private MyObject myObject;

    public ThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        MyObject.a();
    }
}
package com.demo19;

public class ThreadB extends Thread {
    private MyObject myObject;

    public ThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        MyObject.b();
    }
}
package com.demo19;

public class run {
    public static void main(String[] args) {
        MyObject myObject1 = new MyObject();
        MyObject myObject2 = new MyObject();
        ThreadA threadA = new ThreadA(myObject1);
        ThreadB threadB = new ThreadB(myObject2);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

執行結果:

執行緒:A 開始時間:1544846287092
執行緒:A 結束時間:1544846290092
執行緒:B 開始時間:1544846290092
執行緒:B 結束時間:1544846290092

通過結論驗證,class鎖可以對類的所有物件例項起作用。

synchronized(class)同步程式碼塊

package com.demo19;

public class MyObject {
     public void a(){
        synchronized (MyObject.class){
            try {
                System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
                Thread.sleep(3000);
                System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void b(){
        synchronized(MyObject.class){
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 開始時間:" + System.currentTimeMillis());
            System.out.println("執行緒:" + Thread.currentThread().getName() + " 結束時間:" + System.currentTimeMillis());
        }
    }
}
package com.demo19;

public class ThreadA extends Thread {
    private MyObject myObject;

    public ThreadA(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.a();
    }
}
package com.demo19;

public class ThreadB extends Thread {
    private MyObject myObject;

    public ThreadB(MyObject myObject) {
        this.myObject = myObject;
    }

    @Override
    public void run() {
        myObject.b();
    }
}
package com.demo19;

public class run {
    public static void main(String[] args) {
        MyObject myObject1 = new MyObject();
        MyObject myObject2 = new MyObject();
        ThreadA threadA = new ThreadA(myObject1);
        ThreadB threadB = new ThreadB(myObject2);
        threadA.setName("A");
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

執行結果:

執行緒:A 開始時間:1544846633091
執行緒:A 結束時間:1544846636092
執行緒:B 開始時間:1544846636092
執行緒:B 結束時間:1544846636092

結論:synchronized(class)與同步靜態方法的作用一樣。