『壹』 java synchronized 公平鎖嗎
在Java中,synchronized就是非公平鎖,它無法保證等待的線程獲取鎖的順序。
關於非公平鎖
非公平鎖即無法保證鎖的獲取是按照請求鎖的順序進行的。這樣就可能導致某個或者一些線程永遠獲取不到鎖。
『貳』 java synchronized 死鎖問題
synchronized(obj){ ... } 稱之為對obj加鎖的同步代碼塊。 你可以這么理解,每一個java對象,都具有一個鎖標記。而這個鎖標記,同時只能分配給一個線程。 有synchronized(o),意思是只有獲得o對象的鎖標記之後,後面的代碼塊才會執行,否則會等待。 回到你的例子。x1和x2是兩個不同的Xianc對象,但是,對於static的屬性來說,任何Xianc對象都共享相同的值。因此,實際上,x1的o1屬性和x2的o1屬性指向同一個對象,而x1的o2屬性和x2的o2屬性也指向相同的對象。 也就是說,Xianc.o1和Xianc.o2表示兩個對象,這兩個對象被x1和x2作為靜態屬性共享。 然後,我們開始考慮鎖標記的事情。程序中創建了兩個線程t1和t2,並首先啟動了t1線程。t1線程與x1綁定,此時執行的是flag == 0的代碼塊。 首先,遇到sync(o2),由於此時o2的鎖標記還沒有被分配,因此t1線程就能獲得o2的鎖標記,進入代碼塊。 進入代碼塊之後,接下來是sleep。由於t1線程sleep之後,釋放了cpu,導致t2線程開始運行。由於t2線程與x2綁定,此時執行的是flag == 1的代碼塊。 這時,t2線程遇到sync(o1)。由於o1的鎖標記沒有被分配,因此t2線程就能獲得o1的鎖標記,進入代碼塊。同樣的,進入代碼塊之後,t2也進入了sleep狀態,釋放了CPU。 過了一段時間,t1率先蘇醒,並被執行。但是執行過程中,會遇到syn(o1)。此時,o1的鎖標記被t2線程占據,t1無法獲得鎖標記,於是t1隻能等待。 在等待過程中,t2也蘇醒了。但是t2遇到了syn(o2),而此時o2的鎖標記被t1占據,因此t2也只能等待。 於是,兩個線程相互等待,就形成了死鎖。 手打,樓主給分
『叄』 java多線程中synchronized關鍵字的用法
由於同一進程內的多個線程共享內存空間 在Java中 就是共享實例 當多個線程試圖同時修改某個實例的內容時 就會造成沖突 因此 線程必須實現共享互斥 使多線程同步
最簡單的同步是將一個方法標記為synchronized 對同一個實例來說 任一時刻只能有一個synchronized方法在執行 當一個方法正在執行某個synchronized方法時 其他線程如果想要執行這個實例的任意一個synchronized方法 都必須等待當前執行 synchronized方法的線程退出此方法後 才能依次執行
但是 非synchronized方法不受影響 不管當前有沒有執行synchronized方法 非synchronized方法都可以被多個線程同時執行
此外 必須注意 只有同一實例的synchronized方法同一時間只能被一個線程執行 不同實例的synchronized方法是可以並發的 例如 class A定義了synchronized方法sync() 則不同實例a sync()和a sync()可以同時由兩個線程來執行
多線程同步的實現最終依賴鎖機制 我們可以想像某一共享資源是一間屋子 每個人都是一個線程 當A希望進入房間時 他必須獲得門鎖 一旦A獲得門鎖 他進去後就立刻將門鎖上 於是B C D就不得不在門外等待 直到A釋放鎖出來後 B C D中的某一人搶到了該鎖(具體搶法依賴於 JVM的實現 可以先到先得 也可以隨機挑選) 然後進屋又將門鎖上 這樣 任一時刻最多有一人在桐羨屋內(使用共享資源)
Java語言規范內置了對多線程的支持 對於Java程序來說 每一個對象實例都有一把 鎖 一旦某個線程獲得了該鎖 別的線程如果希望獲得該鎖 只能等待這個線程釋放鎖之後 獲得鎖的方法只有一個 就是synchronized關鍵字 例如
public class SharedResource {
private int count = ;
public int getCount() { return count; }
public synchronized void setCount(int count) { unt = count; }
}
同步方法public synchronized void setCount(int count) { unt = count; } 事實上相當於
public void setCount(int count) {
synchronized(this) { // 在此獲得this鎖
unt = count;
} // 在此釋放this鎖
}
紅色部分表示需要同步的代碼段 該區域為 危險區域 如果兩個以上局滲拍的線程同時執行 會引發沖突 因此 要更改SharedResource的內部狀態 必須先獲得SharedResource實例的鎖
退出synchronized塊時 線程擁有的鎖自動釋放 於是 別的線程又可以獲取該鎖了
為了提高性能 不一定要鎖定this 例如 SharedResource有兩個獨立變化的變數
public class SharedResouce {
private int a = ;
private int b = ;
public synchronized void setA(int a) { this a = a; }
public synchronized void setB(int b) { this b = b; }
}
若同步整個方法 則setA()的時候無法setB() setB()時喊飢無法setA() 為了提高性能 可以使用不同對象的鎖
public class SharedResouce {
private int a = ;
private int b = ;
private Object sync_a = new Object()
private Object sync_b = new Object()
public void setA(int a) {
synchronized(sync_a) {
this a = a;
}
}
public synchronized void setB(int b) {
synchronized(sync_b) {
this b = b;
}
lishixin/Article/program/Java/gj/201311/27512
『肆』 Java怎麼使用synchronized聲明一個變數
首先要說明的是,java里不能直接使用synchronized聲明一個變數,而是使用synchronized去修飾一個代碼塊或一個方法。x0dx0ax0dx0a詳細說明如下:x0dx0ax0dx0a synchronized用來修飾一個方法或者一個代碼塊,它用來保證在同一時刻最多隻有一個線程執行該段代碼。x0dx0a 一、當兩個並發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另簡圓一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。x0dx0a 二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。x0dx0a 三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪明悉問將被阻塞。x0dx0a 四、第三激咐乎個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。x0dx0a 五、以上規則對其它對象鎖同樣適用。x0dx0ax0dx0a示例代碼:x0dx0apublic class Thread1 implements Runnable { x0dx0a public void run() { x0dx0a synchronized(this) { x0dx0a for (int i = 0; i < 5; i++) { x0dx0a System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); x0dx0a } x0dx0a } x0dx0a } x0dx0a public static void main(String[] args) { x0dx0a Thread1 t1 = new Thread1(); x0dx0a Thread ta = new Thread(t1, "A"); x0dx0a Thread tb = new Thread(t1, "B"); x0dx0a ta.start(); x0dx0a tb.start(); x0dx0a }x0dx0a}x0dx0a結果: x0dx0a A synchronized loop 0 x0dx0a A synchronized loop 1 x0dx0a A synchronized loop 2 x0dx0a A synchronized loop 3 x0dx0a A synchronized loop 4 x0dx0a B synchronized loop 0 x0dx0a B synchronized loop 1 x0dx0a B synchronized loop 2 x0dx0a B synchronized loop 3 x0dx0a B synchronized loop 4
『伍』 Java多線程初學者指南(10):使用Synchronized關鍵字同步類方法
要想解決 臟數據 的問題 最簡單的方法就是使用synchronized關鍵字來使run方法同步 代碼如下
publicsynchronizedvoidrun(){}
從上面的代碼可以看出 只要在void和public之間加上synchronized關鍵字 就可以使run方法同步 也就是說 對於同一個Java類的對象實例 run方法同時只能被一個線程調用 並當前的run執行完後 才能被其他的線程調用 即使當前線程執行到了run方法中的yield方法 也只是暫停了一下 由於其他線程無法執行run方法 因此 最終還是會由當前的線程來繼續執行 先看看下面的代碼
sychronized關鍵字只和一個對象實例綁定
classTest{publicsynchronizedvoidmethod(){}納察}{privateTesttest;publicvoidrun() { thod(); } publicSync(Testtest) { this test=test; } publicstaticvoidmain(String[]args)throwsException { Testtest =newTest(); Testtest =newTest(); Syncsync =newSync(test ); Syncsync =newSync(test ); newThread(sync ) start(); newThread(sync ) start(); } }
在Test類中的method方法是同步的 但上面的代碼建立了兩個Test類的實例 因此 test 和test 的method方法是分別執行的 要想讓method同步 必須在建立仿茄升Sync類的實例時向它的構造方法中傳入同一個Test類的實例 如下面的代碼所示
Syncsync =newSync(test );
不僅可以使用synchronized來同步非靜態方法 也可以使用synchronized來同步靜態方法 如可以按如下方式來定義method方法
classTest{ (){}}
建立Test類的對象實例如下
Testtest=newTest();
對於靜態方法來說 只要加上了synchronized關鍵字 這個方法就是同步的 無論是使用thod() 還是使用thod()來調用method方法 method都是同步的 並不存在非靜態方法的多個實例的問題
在 種設計模式中的單件(Singleton)模式如果按傳統的方法設計 也是線程不安全的 下面的代碼是一個線程不安全的單件模式
packagetest;//線程安全的Singleton模式classSingleton{privatestaticSingletonsample;privateSingleton(){備老}(){if(sample==null){Thread yield();//為了放大Singleton模式的線程不安全性sample=newSingleton();}returnsample;}}{publicvoidrun(){Singletonsingleton=Singleton getInstance();System out println(singleton hashCode());}publicstaticvoidmain(String[]args){Threadthreads[]=newThread[ ];for(inti= ;i<threads length;i++)threads[i]=newMyThread();for(inti= ;i<threads length;i++)threads[i] start();}}
在上面的代碼調用yield方法是為了使單件模式的線程不安全性表現出來 如果將這行去掉 上面的實現仍然是線程不安全的 只是出現的可能性小得多
程序的運行結果如下
上面的運行結果可能在不同的運行環境上有所有同 但一般這五行輸出不會完全相同 從這個輸出結果可以看出 通過getInstance方法得到的對象實例是五個 而不是我們期望的一個 這是因為當一個線程執行了Thread yield()後 就將CPU資源交給了另外一個線程 由於在線程之間切換時並未執行到創建Singleton對象實例的語句 因此 這幾個線程都通過了if判斷 所以 就會產生了建立五個對象實例的情況(可能創建的是四個或三個對象實例 這取決於有多少個線程在創建Singleton對象之前通過了if判斷 每次運行時可能結果會不一樣)
要想使上面的單件模式變成線程安全的 只要為getInstance加上synchronized關鍵字即可 代碼如下
(){}
當然 還有更簡單的方法 就是在定義Singleton變數時就建立Singleton對象 代碼如下
=newSingleton();
然後在getInstance方法中直接將sample返回即可 這種方式雖然簡單 但不知在getInstance方法中創建Singleton對象靈活 讀者可以根據具體的需求選擇使用不同的方法來實現單件模式
在使用synchronized關鍵字時有以下四點需要注意
synchronized關鍵字不能繼承
雖然可以使用synchronized來定義方法 但synchronized並不屬於方法定義的一部分 因此 synchronized關鍵字不能被繼承 如果在父類中的某個方法使用了synchronized關鍵字 而在子類中覆蓋了這個方法 在子類中的這個方法默認情況下並不是同步的 而必須顯式地在子類的這個方法中加上synchronized關鍵字才可以 當然 還可以在子類方法中調用父類中相應的方法 這樣雖然子類中的方法不是同步的 但子類調用了父類的同步方法 因此 子類的方法也就相當於同步了 這兩種方式的例子代碼如下
在子類方法中加上synchronized關鍵字
classParent{ publicsynchronizedvoidmethod(){}}classChildextendsParent{ publicsynchronizedvoidmethod(){}}
在子類方法中調用父類的同步方法
classParent{ publicsynchronizedvoidmethod(){}}classChildextendsParent{publicvoidmethod(){thod();}}
在定義介面方法時不能使用synchronized關鍵字
構造方法不能使用synchronized關鍵字 但可以使用下節要討論的synchronized塊來進行同步
synchronized可以自由放置
在前面的例子中使用都是將synchronized關鍵字放在方法的返回類型前面 但這並不是synchronized可放置唯一位置 在非靜態方法中 synchronized還可以放在方法定義的最前面 在靜態方法中 synchronized可以放在static的前面 代碼如下
publicsynchronizedvoidmethod();synchronizedpublicvoidmethod();();();();
但要注意 synchronized不能放在方法返回類型的後面 如下面的代碼是錯誤的
publicvoidsynchronizedmethod();();
synchronized關鍵字只能用來同步方法 不能用來同步類變數 如下面的代碼也是錯誤的
publicsynchronizedintn= ;publicstaticsynchronizedintn= ;
雖然使用synchronized關鍵字同步方法是最安全的同步方式 但大量使用synchronized關鍵字會造成不必要的資源消耗以及性能損失 雖然從表面上看synchronized鎖定的是一個方法 但實際上synchronized鎖定的是一個類 也就是說 如果在非靜態方法method 和method 定義時都使用了synchronized 在method 未執行完之前 method 是不能執行的 靜態方法和非靜態方法的情況類似 但靜態和非靜態方法不會互相影響 看看如下的代碼
packagetest;publicclassMyThread extendsThread{publicStringmethodName;publicstaticvoidmethod(Strings){System out println(s);while(true);}publicsynchronizedvoidmethod (){method( 非靜態的method 方法 );}publicsynchronizedvoidmethod (){method( 非靜態的method 方法 );} (){method( 靜態的method 方法 );} (){method( 靜態的method 方法 );}publicvoidrun(){try{getClass() getMethod(methodName) invoke(this);}catch(Exceptione){}}publicstaticvoidmain(String[]args)throwsException{MyThread myThread =newMyThread ();for(inti= ;i<= ;i++){thodName= method +String valueOf(i);newThread(myThread ) start();sleep( );}}}
運行結果如下
非靜態的method 方法靜態的method 方法
lishixin/Article/program/Java/gj/201311/27526
『陸』 java中synchronized函數鎖,鎖的是什麼
修飾方法就代表鎖的是此方法體,如 public synchronized int cal(){...} 表示每次訪問此方法都只能一個線程訪問,其他的要等待訪問完了才能進入此方法,這是競爭鎖,synchronized(obj)鎖的是obj,代表只有獲取了此obj鎖,才能繼續訪問,更高級的推薦使用Lock或ReentrainLock。
『柒』 初學Java多線程:使用Synchronized塊同步方法
synchronized關鍵字有兩種用法 第一種就是在《使用Synchronized關鍵字同步類方法》一文中所介紹的直接用在方法的定義中 另外一種就是synchronized塊 我們不僅可以通過synchronized塊來同步一個對象變數巧頃 也可以使用synchronized塊來同步類中的靜態孝寬陸方法和非靜態方法
synchronized塊的語法如下
public void method()
{
… …
synchronized(表達式)
{
… …
}
}
一 非靜態類方法的同步
從《使用Synchronized關鍵字同步類方法》一文中我們知道使用synchronized關鍵字來定義方法就會鎖定類中所有使用synchronzied關鍵字定義的靜態方法或非靜態方法 但這並不好理解 而如果使用synchronized塊來達到同樣的效果 就不難理解為什麼會產生這種效果了 如果想使用synchronized塊來鎖定類中所有的同步非靜態方法 需要使用this做為synchronized塊的參數傳入synchronized塊國 代碼如下
通過synchronized塊同步非靜態方法
public class SyncBlock
{
public void method ()
{
synchronized(this) // 相當於對method 方法使用synchronized關鍵字
{
… …
}
}
public void method ()
{
synchronized(this) // 相當於對method 方法使用synchronized關鍵字
{
… …
}
}
public synchronized void method ()
{
… …
}
}
在上面的代碼中的method 和method 方法中使用了synchronized塊 而第 行的method 方法仍然使用synchronized關鍵字來定義方法 在使用同一個SyncBlock類實例時 這三個方法只要有一個正在執行 其他兩個方法就會因未獲得同步鎖而被阻塞 在使用synchronized塊時要想達到和synchronized關鍵字同樣的效果 必須將所有的代碼都寫在synchronized塊中 否則 將無法使當前方法中的所有代碼和其他的方法同步
除了使用this做為synchronized塊的參數外 還可以使用SyncBlock this作為synchronized塊的參數來達到同樣的效果
在內類(InnerClass)的方法中使用synchronized塊來時 this只表示內類 和外類(OuterClass)沒有關系 但內類的非靜態方法可以和外類的非靜態方法同步 如在內類InnerClass中加一個method 方法 並使method 方法和SyncBlock的三個方法同步 代碼如下
使內類的非靜態方法和外類的非靜態方法同步
public class SyncBlock
{
… …
class InnerClass
{
public void method ()
{
synchronized(SyncBlock this)
{
… …
}
}
}
… …
}
在上面SyncBlock類的新版本中 InnerClass類的method 方法和SyncBlock類的其他三個方法同步 因此 method method method 和method 四個方法在同一時間巧手只能有一個方法執行
Synchronized塊不管是正常執行完 還是因為程序出錯而異常退出synchronized塊 當前的synchronized塊所持有的同步鎖都會自動釋放 因此 在使用synchronized塊時不必擔心同步鎖的釋放問題
二 靜態類方法的同步
由於在調用靜態方法時 對象實例不一定被創建 因此 就不能使用this來同步靜態方法 而必須使用Class對象來同步靜態方法 代碼如下
通過synchronized塊同步靜態方法
public class StaticSyncBlock
{
public static void method ()
{
synchronized(StaticSyncBlock class)
{
… …
}
}
public static synchronized void method ()
{
… …
}
}
在同步靜態方法時可以使用類的靜態欄位class來得到Class對象 在上例中method 和method 方法同時只能有一個方法執行 除了使用class欄位得到Class對象外 還可以使用實例的getClass方法來得到Class對象 上例中的代碼可以修改如下
使用getClass方法得到Class對象
public class StaticSyncBlock
{
public static StaticSyncBlock instance;
public StaticSyncBlock()
{
instance = this;
}
public static void method ()
{
synchronized(instance getClass())
{
}
}
}
在上面代碼中通過一個public的靜態instance得到一個StaticSyncBlock類的實例 並通過這個實例的getClass方法得到了Class對象(一個類的所有實例通過getClass方法得到的都是同一個Class對象 因此 調用任何一個實例的getClass方法都可以) 我們還可以通過Class對象使不同類的靜態方法同步 如Test類的靜態方法method和StaticSyncBlock類的兩個靜態方法同步 代碼如下
Test類的method方法和StaticSyncBlock類的method method 方法同步
public class Test
{
public static void method()
{
synchronized(StaticSyncBlock class)
{
}
}
}
lishixin/Article/program/Java/gj/201311/27374
『捌』 請問java中的lock和synchronized區別是什麼
1、ReentrantLock 擁有Synchronized相同的並發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候:
線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定;
如果使用 synchronized ,如果A不釋放,B將一直等下去,不能被中斷;
如果 使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以後,中斷等待,而干別的事情。
2、synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在代碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實現的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中。
3、在資源競爭不是很激烈的情況下,Synchronized的性能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常態。