Java面試之synchronized 和 static synchronized

 

​面試題:java

答案: 面試

不能編程

不能設計模式

不能多線程

不能併發

this

 

正文url

 

概述spa

經過分析這兩個用法的分析,咱們能夠理解java中鎖的概念。一個是實例鎖(鎖在某一個實例對象上,若是該類是單例,那麼該鎖也具備全局鎖的概念),一個是全局鎖(該鎖針對的是類,不管實例多少個對象,那麼線程都共享該鎖)。實例鎖對應的就是synchronized關鍵字,而類鎖(全局鎖)對應的就是static synchronized(或者是鎖在該類的class或者classloader對象上)。線程

 

區別

synchronized關鍵字

synchronized做用是對類的當前實例(對象)加鎖。可使用synchronized關鍵字來標記一個方法或者代碼塊,當某個線程調用該對象的synchronized方法或者訪問synchronized代碼塊時,這個線程便得到了該對象的鎖,其餘線程暫時沒法訪問這個方法,只有等待這個方法執行完畢或者代碼塊執行完畢,這個線程纔會釋放該對象的鎖(Java 併發編程)。

synchronized代碼塊【synchronized(synObject)】使用起來比synchronized方法要靈活得多。由於也許一個方法中只有一部分代碼只須要同步,若是此時對整個方法用synchronized進行同步,會影響程序執行效率。而使用synchronized代碼塊就能夠避免這個問題(同步對象或類屬性),synchronized代碼塊能夠實現只對須要同步的地方進行同步。

與Lock的區別:1. synchronized是Java語言的關鍵字,所以是內置特性,Lock是一個類(java.util.concurrent.locks包),經過這個類能夠實現同步訪問;2. synchronized不須要用戶去手動釋放鎖,當synchronized方法或者synchronized代碼塊執行完以後,系統會自動讓線程釋放對鎖的佔用。Lock則必需要用戶去手動釋放鎖,若是沒有主動釋放鎖,就有可能致使出現死鎖現象。

static synchronized:

每一個類有一個鎖,它能夠用來控制對static數據成員的併發訪問。訪問static synchronized方法佔用的是類鎖,而訪問非static synchronized方法佔用的是對象鎖。

static synchronized控制類的全部實例(對象)的訪問(相應代碼塊)。synchronized至關於 this.synchronized,static synchronized至關於Something.synchronized

 

一個日本做者-結成浩的《java多線程設計模式》有這樣的一個列子:

 pulbic class Something(){ 
public synchronized void isSyncA(){}

public synchronized void isSyncB(){}

public static synchronized void cSyncA(){}

public static synchronized void cSyncB(){}

}

那麼,假若有Something類的兩個實例x與y,那麼下列各組方法被多線程同時訪問的狀況是怎樣的?

a. x.isSyncA()與x.isSyncB()
b. x.isSyncA()與y.isSyncA()
c. x.cSyncA()與y.cSyncB()
d. x.isSyncA()與Something.cSyncA()

這裏,很清楚的能夠判斷:

  1. 都是對同一個實例(x)的synchronized域訪問,所以不能被同時訪問。(多線程中訪問x的不一樣synchronized域不能同時訪問)

    若是在多個線程中訪問x.isSyncA(),由於仍然是對同一個實例,且對同一個方法加鎖,因此多個線程中也不能同時訪問。(多線程中訪問x的同一個synchronized域不能同時訪問)

  2. 是針對不一樣實例的,所以能夠同時被訪問(對象鎖對於不一樣的對象實例沒有鎖的約束)

  3. 由於是static synchronized,因此不一樣實例之間仍然會被限制,至關於Something.isSyncA()與 Something.isSyncB()了,所以不能被同時訪問。

  4. 書上的 答案是能夠被同時訪問的,答案理由是synchronzied的是實例方法與synchronzied的類方法因爲鎖定(lock)不一樣的緣由。

我的分析也就是synchronized 與static synchronized 至關於兩幫派,各自管各自,相互之間就無約束了,能夠被同時訪問。

舉個例子:

public class TestSynchronized {
    public synchronized void test1() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
        }
    }

    public static synchronized void test2() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
        }
    }

    public static void main(String[] args) {
        final TestSynchronized myt2 = new TestSynchronized();
        Thread test1 = new Thread(new Runnable() {
            public void run() {
                myt2.test1();
            }
        }, "test1");
        Thread test2 = new Thread(new Runnable() {
            public void run() {
                TestSynchronized.test2();
            }
        }, "test2");
        test1.start();
        test2.start();
    }
} 
test1 : 4
test2 : 4
test1 : 3
test2 : 3
test2 : 2
test1 : 2
test2 : 1
test1 : 1
test1 : 0
test2 : 0

 

上面代碼synchronized同時修飾靜態方法和實例方法,可是運行結果是交替進行的,這證實了類鎖和對象鎖是兩個不同的鎖,控制着不一樣的區域,它們是互不干擾的。一樣,線程得到對象鎖的同時,也能夠得到該類鎖,即同時得到兩個鎖,這是容許的。

結論

A: synchronized static是某個類的範圍,synchronized static cSync{}防止多個線程中多個實例同時訪問這個 類中的synchronized static 方法。它能夠對類的全部對象實例起做用。

B: synchronized 是某實例的範圍,synchronized isSync(){}防止多個線程中這一個實例同時訪問這個類的synchronized 方法。

其實總結起來很簡單。

  • 一個鎖的是類對象,一個鎖的是實例對象。

  • 若類對象被lock,則類對象的全部同步方法全被lock;

  • 若實例對象被lock,則該實例對象的全部同步方法全被lock。

相關文章
相關標籤/搜索