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)同步類中的靜態(tài)方法和非靜態(tài)方法。
第一種:非靜態(tài)方法的同步
從java相關(guān)語(yǔ)法可以知道使用synchronized關(guān)鍵字來(lái)定義方法就會(huì)鎖定類中所用使用synchroniezd關(guān)鍵字定義的靜態(tài)方法和非靜態(tài)方法,但是這有點(diǎn)不好理解,如果要synchronized塊,來(lái)達(dá)到這樣的效果,就不難理解為什么會(huì)產(chǎn)生這種效果了,如果使用synchronized來(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)類中使用synchronized塊中,this只表示內(nèi)類,和外類(OuterClass)沒(méi)有關(guān)系。但是內(nèi)類中的非靜態(tài)方法和外類的非靜態(tài)方法也可以同步。如果在內(nè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í)可以使用類的靜態(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è)類的所有實(shí)例通過(guò)getClass方法得到的都是同一個(gè)Class對(duì)象)。我們也可以通過(guò)class使不同類的靜態(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的用法詳解(四種用法)
- 深入理解java中的synchronized關(guān)鍵字
- Java中Synchronized的用法解析
- java多線程編程之使用Synchronized塊同步變量
- Java synchronized鎖升級(jí)jol過(guò)程詳解
- 詳解Java中synchronized關(guān)鍵字的死鎖和內(nèi)存占用問(wèn)題
- Java 多線程同步 鎖機(jī)制與synchronized深入解析
- Java中synchronized的幾種使用方法
- Java 同步鎖(synchronized)詳解及實(shí)例
- 淺談Java并發(fā)編程之synchronized有序性誤區(qū)
相關(guān)文章
關(guān)于maven打包時(shí)的報(bào)錯(cuò): Return code is: 501 , ReasonPhrase:HTTPS Requ
這篇文章主要介紹了關(guān)于maven打包時(shí)的報(bào)錯(cuò): Return code is: 501 , ReasonPhrase:HTTPS Required,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
利用Spring Cloud Config結(jié)合Bus實(shí)現(xiàn)分布式配置中心的步驟
這篇文章主要介紹了利用Spring Cloud Config結(jié)合Bus實(shí)現(xiàn)分布式配置中心的相關(guān)資料,文中通過(guò)示例代碼將實(shí)現(xiàn)的步驟一步步介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友下面來(lái)一起看看吧2018-05-05
SpringBoot項(xiàng)目集成日志的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot項(xiàng)目集成日志的實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
SpringBoot整合mybatis-generator插件流程詳細(xì)講解
這篇文章主要介紹了SpringBoot整合mybatis-generator插件流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-02-02
spring validation多層對(duì)象校驗(yàn)教程
這篇文章主要介紹了spring validation多層對(duì)象校驗(yàn)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
java教程之java程序編譯運(yùn)行圖解(java程序運(yùn)行)
最近重新復(fù)習(xí)了一下java基礎(chǔ),在使用javap的過(guò)程中遇到了一些問(wèn)題,這里便講講對(duì)于一個(gè)類文件如何編譯、運(yùn)行、反編譯的。也讓自己加深一下印象2014-03-03
Java捕獲ThreadPoolExecutor內(nèi)部線程異常的四種方法
這篇文章主要為大家詳細(xì)介紹了Java捕獲ThreadPoolExecutor內(nèi)部線程異常的四種方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2025-03-03
Java線程池隊(duì)列LinkedBlockingDeque
這篇文章主要為大家介紹了Java線程池隊(duì)列LinkedBlockingDeque示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12

