標籤:
對於並發工作,你永遠不知道一個線程何時運行,你需要某種方式來避免兩個任務訪問相同的資源,即要避免資源競爭,至少在關鍵代碼上不能出現這樣的情況,否則多個線程同時對某個記憶體地區操作會導致資料破壞。
程式碼中的臨界區是需要互斥訪問的,同一時刻只能有一個線程來訪問臨界區,也就是線程對臨界區的訪問時互斥的。
競爭條件:當多個線程同時訪問某個共用的記憶體地區並且對其進行讀寫操作時,就會出現資料破壞。這就是競爭條件。避免競爭條件的方法是synchronized加鎖。
範例,設有一個現成,該線程的任務是對共用變數count值+1。設count值的初始值為0,開闢1000個相同的線程,那麼線程執行完後,count的值應該為1000(因為每個線程中都對count做了加一操作),但是實際效果會出現錯誤,這是因為出現了競爭條件。
解決辦法:使用synchronized鎖,
先定義一個object對象:
private final static Object lockObj = new Object();
下面即是同步塊,在同步塊中進行關鍵操作。
synchronized(lockObj){syn.count = syn.count+1;temp = temp+1;}
-------------------------------------------------------------------------------
下面是正題
JAVA中synchronized關鍵字能夠作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步語句塊。假如再細的分類,synchronized可作用於instance變數、object reference(對象引用,例如this)、static函數和class literals(類名稱字面常量)身上。下面討論synchronized用到不同地方對代碼產生的影響:
假設P1、P2是同一個類的不同對象,這個類中定義了以下幾種情況的同步塊或同步方法,P1、P2就都能夠調用他們。
1.把synchronized當作函數修飾符時,範例程式碼如下:
public synchronized void method(){
//….
}
這也就是同步方法,那這時synchronized鎖定的是哪個對象呢?他鎖定的是調用這個同步方法對象。也就是說,當一個對象P1在不同的線程中執行這個同步方法時,他們之間會形成互斥,達到同步的效果。但是這個對象所屬的Class所產生的另一對象P2卻能夠任意調用這個被加了synchronized關鍵字的方法。上邊的範例程式碼等同於如下代碼:
public void method()
{
synchronized (this) // (1)
{
//…..
}
}
(1)處的this指的是什麼呢?他指的就是調用這個方法的對象,如P1。可見,同步方法實質是將synchronized作用於Object Reference。那個拿到了P1對象鎖的線程,才能夠調用P1的同步方法,而對P2而言,P1這個鎖和他毫不相干,程式也可能在這種情形下擺脫同步機制的控制,造成資料混亂。
2.同步塊,範例程式碼如下:
public void method(SomeObject so) {
synchronized(so)
{
//…..
}
}
這時,鎖就是so這個對象,誰拿到這個鎖誰就能夠運行他所控制的那段代碼。當有一個明確的對象作為鎖時,就能夠這樣寫程式,但當沒有明確的對象作為鎖,只是想讓一段代碼同步時,能夠建立一個特別的instance變數(它得是個對象)來充當鎖:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特別的instance變數
Public void method()
{
synchronized(lock) { //… }
}
//…..
}
註:零長度的byte數組對象建立起來將比任何對象都經濟。查看編譯後的位元組碼:產生零長度的byte[]對象只需3條作業碼,而Object lock = new Object()則需要7行作業碼。
3.將synchronized作用於static 函數,範例程式碼如下:
Class Foo
{
public synchronized static void method1() // 同步的static 函數
{
//….
}
public void method2()
{
synchronized(Foo.class) // class literal(類名稱字面常量)
}
}
代碼中的method2()方法是把class literal作為鎖的情況,他和同步的static函數產生的效果是相同的,取得的鎖很特別,是當前調用這個方法的對象所屬的類(Class類,而不再是由這個Class產生的某個具體對象了)。
轉載請註明:struts教程網 » synchronized的深刻認識
如何來定義共用變數:
1、在主類中定義一個final變數,讓其在其他線程中也可以執行。
2、使用static定義線程公用的成員變數,在一個類實現runnable介面,其中定義一個static變數,這個變數就為所有使用此介面的類對象所共用,即所有的類對象共用一份這個變數的拷貝。
1、java中synchronize可以用來給對象、代碼塊等加鎖。synchronize關鍵字可以出現在函數外,也可以出現在函數體
2、沒有volatile就沒有java多線程
3、Thread.join()可以設定讓當前線程執行完畢後再執行其他線程,這在控制線程的執行順序上很有用。
下面通過一個代碼來描述java多線程中可能出現的資源競爭條件(race condition)問題。
java中synchronize鎖 volatile thread.join()方法的使用