1. 程式人生 > >同步方法與同步塊的區別

同步方法與同步塊的區別

java使用synchronized同步,分為四種情況:

  例項方法同步

  例項方法中同步塊

  靜態方法同步

  靜態方法中同步塊

我們從兩個方面來說他們的不同,一個是同步方法和同步塊的區別,一個是靜態和非靜態的區別。

同步方法就是在方法前加關鍵字synchronized,然後被同步的方法一次只能有一個執行緒進入,其他執行緒等待。而同步方法則是在方法內部使用大括號使得一個程式碼塊得到同步。同步塊會有一個同步的”目標“,使得同步塊更加靈活一些(同步塊可以通過”目標“決定需要鎖定的物件)。一般情況下,如果此”目標“為this,那麼同步方法和同步塊沒有太大的區別。

另外,通過反編譯可以看出,同步塊比同步方法多了兩個指令。因此同步方法是比同步塊要快一些。

非靜態和靜態的區別主要在於(以同步方法為例):非靜態的同步方法是鎖定類的例項的,而靜態的同步方法是鎖定類的;

也就是說,對於非靜態的同步方法,在同一時刻,一個類的一個例項中,只有一個執行緒能進入同步的方法。但是對於多個例項,每一個例項的一個執行緒都可以進入同一同步的方法。

Demo1:一個例項的多個執行緒,一次只能有一個執行緒進入非靜態同步的方法。

package SynchronizedTest;

/**
 * Created by carrot on 16/8/31.
 */
public class SyncFunc {

    public synchronized void func1() {
        System.out.println(Thread.currentThread().getName() + " is running");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " is stop");
    }

    public static void main(String[] args) {

        NewThread newThread1 = new NewThread();
        NewThread newThread2 = new NewThread();
        NewThread newThread3 = new NewThread();

        newThread1.start();
        newThread2.start();
        newThread3.start();

    }
}

class NewThread extends Thread {

    static SyncFunc syncFunc = new SyncFunc();

    @Override
    public void run() {
        syncFunc.func1();
    }

}

結果:
Thread-0 is running
Thread-0 is stop
Thread-2 is running
Thread-2 is stop
Thread-1 is running
Thread-1 is stop

從結果可見,每次只能有一個執行緒進入非靜態同步的方法。

Demo2:多個例項的執行緒能同時進入非靜態同步的方法。

package SynchronizedTest;

/**
 * Created by carrot on 16/8/31.
 */
public class SyncFunc {

    public synchronized void func1() {
        System.out.println(Thread.currentThread().getName() + " is running");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " is stop");
    }

    public static void main(String[] args) {

        NewThread newThread1 = new NewThread();
        NewThread newThread2 = new NewThread();
        NewThread newThread3 = new NewThread();

        newThread1.start();
        newThread2.start();
        newThread3.start();

    }
}

class NewThread extends Thread {

    SyncFunc syncFunc = new SyncFunc();

    @Override
    public void run() {
        syncFunc.func1();
    }

}

結果:
Thread-0 is running
Thread-1 is running
Thread-2 is running
Thread-0 is stop
Thread-2 is stop
Thread-1 is stop

從結果可以看出,多個例項的執行緒同時進入了同步的非靜態方法。

Demo3:多個例項的執行緒進入靜態的同步方法。

package SynchronizedTest;

/**
 * Created by carrot on 16/8/31.
 */
public class SyncFunc {

    public static synchronized void func1() {
        System.out.println(Thread.currentThread().getName() + " is running");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " is stop");
    }

    public static void main(String[] args) {

        NewThread newThread1 = new NewThread();
        NewThread newThread2 = new NewThread();
        NewThread newThread3 = new NewThread();

        newThread1.start();
        newThread2.start();
        newThread3.start();

    }
}

class NewThread extends Thread {

    SyncFunc syncFunc = new SyncFunc();

    @Override
    public void run() {
        syncFunc.func1();
    }

}

結果:
Thread-0 is running
Thread-0 is stop
Thread-2 is running
Thread-2 is stop
Thread-1 is running
Thread-1 is stop

從結果可以看出,對於同一個物件的多個例項,在進入靜態的同步方法時,一次只能有一個類例項進入。