面試題:java
答案: 面試
不能編程
不能設計模式
不能多線程
不能併發
能this
正文url
概述spa
經過分析這兩個用法的分析,咱們能夠理解java中鎖的概念。一個是實例鎖(鎖在某一個實例對象上,若是該類是單例,那麼該鎖也具備全局鎖的概念),一個是全局鎖(該鎖針對的是類,不管實例多少個對象,那麼線程都共享該鎖)。實例鎖對應的就是synchronized關鍵字,而類鎖(全局鎖)對應的就是static synchronized(或者是鎖在該類的class或者classloader對象上)。線程
區別
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數據成員的併發訪問。訪問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()
這裏,很清楚的能夠判斷:
都是對同一個實例(x)的synchronized域訪問,所以不能被同時訪問。(多線程中訪問x的不一樣synchronized域不能同時訪問)
若是在多個線程中訪問x.isSyncA(),由於仍然是對同一個實例,且對同一個方法加鎖,因此多個線程中也不能同時訪問。(多線程中訪問x的同一個synchronized域不能同時訪問)
是針對不一樣實例的,所以能夠同時被訪問(對象鎖對於不一樣的對象實例沒有鎖的約束)
由於是static synchronized,因此不一樣實例之間仍然會被限制,至關於Something.isSyncA()與 Something.isSyncB()了,所以不能被同時訪問。
書上的 答案是能夠被同時訪問的,答案理由是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。