Java中synchronized關(guān)鍵字修飾方法同步的用法詳解
Java的最基本的同步方式,即使用synchronized關(guān)鍵字來(lái)控制一個(gè)方法的并發(fā)訪問(wèn)。 每一個(gè)用synchronized關(guān)鍵字聲明的方法都是臨界區(qū)。在Java中,同一個(gè)對(duì)象的臨界區(qū),在同一時(shí)間只有一個(gè)允許被訪問(wèn)。
靜態(tài)方法則有不同的行為。用synchronized關(guān)鍵字聲明的靜態(tài)方法,同時(shí)只能夠被一個(gè)執(zhí)行線程訪問(wèn),但是其他線程可以訪問(wèn)這個(gè)對(duì)象的非靜態(tài)的synchronized方法。必須非常謹(jǐn)慎這一點(diǎn),因?yàn)閮蓚€(gè)線程可以同時(shí)訪問(wèn)一個(gè)對(duì)象的兩個(gè)不同的synchronized方法,即其中一個(gè)是靜態(tài)synchronized方法,另一個(gè)是非靜態(tài)synchronized方法。如果兩個(gè)方法都改變了相同的數(shù)據(jù),將會(huì)出現(xiàn)數(shù)據(jù)不一致的錯(cuò)誤。
synchronized塊的語(yǔ)法如下:
public void method() { synchronized(表達(dá)式) { } }
synchronized關(guān)鍵字有兩種用法,一種是只用于方法的定義中,另外一種是synchronized塊,我們不僅可以使用synchronized來(lái)同步一個(gè)對(duì)象變量,你也可以通synchronizedl來(lái)同步類(lèi)中的靜態(tài)方法和非靜態(tài)方法。
第一種:非靜態(tài)方法的同步
從java相關(guān)語(yǔ)法可以知道使用synchronized關(guān)鍵字來(lái)定義方法就會(huì)鎖定類(lèi)中所用使用synchroniezd關(guān)鍵字定義的靜態(tài)方法和非靜態(tài)方法,但是這有點(diǎn)不好理解,如果要synchronized塊,來(lái)達(dá)到這樣的效果,就不難理解為什么會(huì)產(chǎn)生這種效果了,如果使用synchronized來(lái)鎖定類(lèi)中所有的同步非靜態(tài)方法,只需要使用this作為synchronized塊的參數(shù)傳入synchronized塊中,代碼如下:
public class Test { public void method1() { synchronized(this) { } } public synchronized void method2() { } } public class Test { public void method1() { synchronized(this) { } } public synchronized void method2() { } }
在內(nèi)類(lèi)中使用synchronized塊中,this只表示內(nèi)類(lèi),和外類(lèi)(OuterClass)沒(méi)有關(guān)系。但是內(nèi)類(lèi)中的非靜態(tài)方法和外類(lèi)的非靜態(tài)方法也可以同步。如果在內(nèi)類(lèi)中加個(gè)方法method3也可以使和Test里面的2個(gè)方法同步,代碼如下:
public class Test { class InnerClass { public void method3() { synchronized(Test.this){ } } } } public class Test { class InnerClass { public void method3() { synchronized(Test.this){ } } } }
上面InnerClass的method3方法與Test的method1和method2方法在同一時(shí)間內(nèi)只能有一個(gè)方法執(zhí)行。
synchronized塊不管是正確執(zhí)行完,還是因?yàn)槌绦虺鲥e(cuò)因異常退出synchronized塊,當(dāng)前的synchronized塊所持有的同步鎖都會(huì)自動(dòng)釋放,因此在使用synchronized塊不必?fù)?dān)心同步鎖的問(wèn)題。
二、靜態(tài)方法的同步
由于在調(diào)用靜態(tài)方法時(shí),對(duì)象實(shí)例不一定被創(chuàng)建,因此,就不能使用this來(lái)同步靜態(tài)方法,而必須使用Class對(duì)象來(lái)同步靜態(tài)方法。代碼如下:
public class Test{ pubic static void method1(){ synchronized(Test.class){ } } public static synchronized void method2(){ } } public class Test{ pubic static void method1(){ synchronized(Test.class){ } } public static synchronized void method2(){ } }
在同步靜態(tài)方法時(shí)可以使用類(lèi)的靜態(tài)字段class來(lái)得到class對(duì)象,在上例中method1和method2方法只有一個(gè)方法執(zhí)行,除了使用class字段可以得到class對(duì)象,還可以通過(guò)實(shí)例的getClass()方法獲取class對(duì)象,代碼如下:
public class Test{ public static Test test; public Test(){ test=this; } public static void method1(){ synchronized(test.getClass()){ } } } public class Test{ public static Test test; public Test(){ test=this; } public static void method1(){ synchronized(test.getClass()){ } } }
在上面的代碼中,我們通過(guò)一個(gè)public的靜態(tài)對(duì)象得到Test的一個(gè)實(shí)例,并通過(guò)這個(gè)實(shí)例的getClass方法獲取一個(gè)class對(duì)象(注意一個(gè)類(lèi)的所有實(shí)例通過(guò)getClass方法得到的都是同一個(gè)Class對(duì)象)。我們也可以通過(guò)class使不同類(lèi)的靜態(tài)方法同步,代碼如下:
public class Test1{ public static void method1(){ synchronized(Test.class){ } } } public class Test1{ public static void method1(){ synchronized(Test.class){ } } }
注意:在使用synchronized塊來(lái)同步方法時(shí),非靜態(tài)方法可以通過(guò)this來(lái)同步,而靜態(tài)方法必須使用class對(duì)象來(lái)同步,但是非靜態(tài)方法也可以通過(guò)使用class來(lái)同步靜態(tài)方法。但是靜態(tài)方法中不能使用this來(lái)同步非靜態(tài)方法。這點(diǎn)在使用synchronized塊需要注意。
Note
synchronized關(guān)鍵字會(huì)降低應(yīng)用程序的性能,因此只能在并發(fā)情景中需要修改共享數(shù)據(jù)的方法上使用它。如果多個(gè)線程訪問(wèn)同一個(gè)synchronized方法,則只有一個(gè)線程可以訪問(wèn),其他線程將等待。如果方法聲明沒(méi)有使用synchronized關(guān)鍵字,所有的線程都能在同一時(shí)間執(zhí)行這個(gè)方法,因而總運(yùn)行時(shí)間降低。如果已知一個(gè)方法不會(huì)被一個(gè)以上線程調(diào)用,則無(wú)需使用synchronized關(guān)鍵字聲明之。
可以遞歸調(diào)用被synchronized聲明的方法。當(dāng)線程訪問(wèn)一個(gè)對(duì)象的同步方法時(shí),它還可以調(diào)用這個(gè)對(duì)象的其他的同步方法,也包含正在執(zhí)行的方法,而不必再次去獲取這個(gè)方法的訪問(wèn)權(quán)。
我們可以通過(guò)synchronized關(guān)鍵字來(lái)保護(hù)代碼塊(而不是整個(gè)方法)的訪問(wèn)。應(yīng)該這樣利用synchronized關(guān)鍵字:方法的其余部分保持在synchronized代碼塊之外,以獲取更好的性能。臨界區(qū)(即同一時(shí)間只能被一個(gè)線程訪問(wèn)的代碼塊)的訪問(wèn)應(yīng)該盡可能的短。例如在獲取一幢樓人數(shù)的操作中,我們只使用synchronized關(guān)鍵字來(lái)保護(hù)對(duì)人數(shù)更新的指令,并讓其他操作不使用共享數(shù)據(jù)。當(dāng)這樣使用synchronized關(guān)鍵字時(shí),必須把對(duì)象引用作為傳入?yún)?shù)。同一時(shí)間只有一個(gè)線程被允許訪問(wèn)這個(gè)synchronized代碼。通常來(lái)說(shuō),我們使用this關(guān)鍵字來(lái)引用正在執(zhí)行的方法所屬的對(duì)象:
synchronized(this){ //Java code }
- 深入理解java中的synchronized關(guān)鍵字
- 詳解Java中synchronized關(guān)鍵字的死鎖和內(nèi)存占用問(wèn)題
- java多線程編程之使用Synchronized關(guān)鍵字同步類(lèi)方法
- Java關(guān)鍵字volatile和synchronized作用和區(qū)別
- JAVA面試題 簡(jiǎn)談你對(duì)synchronized關(guān)鍵字的理解
- Java中使用synchronized關(guān)鍵字實(shí)現(xiàn)簡(jiǎn)單同步操作示例
- 舉例講解Java中synchronized關(guān)鍵字的用法
- 實(shí)例解析Java中的synchronized關(guān)鍵字與線程安全問(wèn)題
- Java關(guān)鍵字synchronized基本使用詳解
相關(guān)文章
10張圖總結(jié)出并發(fā)編程最佳學(xué)習(xí)路線
這篇文章主要介紹了并發(fā)編程的最佳學(xué)習(xí)路線,文中通過(guò)圖片介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08SpringBoot整合Swagger和Actuator的使用教程詳解
Swagger 是一套基于 OpenAPI 規(guī)范構(gòu)建的開(kāi)源工具,可以幫助我們?cè)O(shè)計(jì)、構(gòu)建、記錄以及使用 Rest API。本篇文章主要介紹的是SpringBoot整合Swagger(API文檔生成框架)和SpringBoot整合Actuator(項(xiàng)目監(jiān)控)使用教程。感興趣的朋友一起看看吧2019-06-06