導航:首頁 > 編程語言 > javasynchronized對象

javasynchronized對象

發布時間:2023-07-21 23:58:24

1. java 多線程 兩個線程訪問兩個對象中不同的synchronized修飾的方法。(方法和對象都是同一個類的)

先上結論:兩個線程訪問不同對象中不同的synchronized方法不會受到synchronized的限制。

程序運行結果之所以這樣,原因在於run()方法的實現導致的。

線程1中,先調用m.test1(),接著Thread.sleep(1000)

線程2中,先Thread.sleep(1000),接著調用m.test2()

主程序中,線程1與2都有可能先開始,無論誰先開始,結果都是線程1中m.test1()先結束,線程2中m.test2()後結束。

因為輪到線程2時,先Thread.sleep(1000),將資源讓給線程1

改進方法,應該在列印時,讓線程sleep

classTest{
synchronizedpublicvoidtest1(){
for(intp=0;p<5;p++){
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
System.out.println("s1.run.TestSynchronized_test1");
}
}

synchronizedpublicvoidtest2(){

for(intp=0;p<5;p++){
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
System.out.println("s2.run.TestSynchronized_test2");
}
}
}

run()方法中直接調用即可

classTestSynchronized_1implementsRunnable{

privateTestm;
publicTestSynchronized_1(Testm){
this.m=m;
}

publicvoidrun(){
m.test1();
}
}

classTestSynchronized_2implementsRunnable{

privateTestm;
publicTestSynchronized_2(Testm){
this.m=m;
}

publicvoidrun(){
m.test2();
}
}

輸出結果如下:

s2.run.TestSynchronized_test 2

s2.run.TestSynchronized_test 2

s1.run.TestSynchronized_test 1

s1.run.TestSynchronized_test 1

s2.run.TestSynchronized_test 2

s1.run.TestSynchronized_test 1

s2.run.TestSynchronized_test 2

s1.run.TestSynchronized_test 1

s2.run.TestSynchronized_test 2

2. Java中線程同步的synchronized()(同步方法塊)這個括弧里的參數是啥

synchronized()、synchronized(this)、synchronized(類名.class)
synchronized加在非靜態方法前和synchronized(this)都是鎖住了這個類的對象,如果多線程訪問,對象不同,就鎖不住,對象固定是一個,就可鎖住。
synchronized(類名.class)和加在靜態方法前,是鎖住了代碼塊,不管多線程訪問的時候對象是不是同一個,能縮小代碼段的范圍就盡量縮小,能在代碼段上加同步就不要再整個方法上加同步,縮小鎖的粒度。

3. 初學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

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

閱讀全文

與javasynchronized對象相關的資料

熱點內容
ipad相冊如何在文件夾中建文件夾 瀏覽:621
和家親這個app有什麼用 瀏覽:575
什麼app裡面有種樹打折 瀏覽:374
編程外掛入門教學 瀏覽:974
pdf黑白轉彩色 瀏覽:725
英國投資加密貨幣嗎 瀏覽:887
看完程序員那麼可愛後的感受 瀏覽:131
廣播在什麼APP能聽 瀏覽:678
阿克曼小車連接什麼app 瀏覽:773
all100編程器 瀏覽:182
加密的內存卡能用嗎 瀏覽:923
linux在線環境 瀏覽:404
java保留兩位小數四捨五入 瀏覽:106
安卓手機怎麼設置中間頁面 瀏覽:387
文檔自動壓縮圖片了怎麼辦 瀏覽:236
和平精英如何換伺服器名稱 瀏覽:517
外國的雲伺服器有沒有中文的 瀏覽:545
top853編程器 瀏覽:966
家用wlfi怎樣加密 瀏覽:675
二手漢鍾螺桿壓縮機 瀏覽:395