亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java多線程編程中synchronized關(guān)鍵字的基礎(chǔ)用法講解

 更新時(shí)間:2016年06月15日 11:59:23   作者:ciding  
Java的synchronized關(guān)鍵字用于修飾線程同步,用以線程資源共享的目的等,下面就帶來(lái)簡(jiǎn)單的Java多線程編程中synchronized關(guān)鍵字的基礎(chǔ)用法講解

多線程編程中,最關(guān)鍵、最關(guān)心的問(wèn)題應(yīng)該就是同步問(wèn)題,這是一個(gè)難點(diǎn),也是核心。
從jdk最早的版本的synchronized、volatile,到j(luò)dk 1.5中提供的java.util.concurrent.locks包中的Lock接口(實(shí)現(xiàn)有ReadLock,WriteLock,ReentrantLock),多線程的實(shí)現(xiàn)也是一步步走向成熟化。
 
同步,它是通過(guò)什么機(jī)制來(lái)控制的呢?第一反應(yīng)就是鎖,這個(gè)在學(xué)習(xí)操作系統(tǒng)與數(shù)據(jù)庫(kù)的時(shí)候,應(yīng)該都已經(jīng)接觸到了。在Java的多線程程序中,當(dāng)多個(gè)程序競(jìng)爭(zhēng)同一個(gè)資源時(shí),為了防止資源的腐蝕,給第一個(gè)訪問(wèn)資源的線程分配一個(gè)對(duì)象鎖,而后來(lái)者需要等待這個(gè)對(duì)象鎖的釋放。
 
是的,Java線程的同步,最關(guān)心的是共享資源的使用。
 
先來(lái)了解一些有哪些線程的共享資源,
從JVM中了解有哪些線程共享的數(shù)據(jù)是需要進(jìn)行協(xié)調(diào):
1,保存在堆中的實(shí)例變量;2,保存在方法區(qū)的類(lèi)變量。
 
而在Java虛擬機(jī)加載類(lèi)的時(shí)候,每個(gè)對(duì)象或類(lèi)都會(huì)與一個(gè)監(jiān)視器相關(guān)聯(lián),用來(lái)保護(hù)對(duì)象的實(shí)例變量或類(lèi)變量;當(dāng)然,如果對(duì)象沒(méi)有實(shí)例變量,或類(lèi)沒(méi)有變量,監(jiān)視器就什么也不監(jiān)視了。
 
為了實(shí)現(xiàn)上面的說(shuō)的監(jiān)視器的互斥性,虛擬機(jī)為每一個(gè)對(duì)象或類(lèi)都關(guān)聯(lián)了一個(gè)鎖(也叫隱形鎖),這里說(shuō)明一下,類(lèi)鎖也是通過(guò)對(duì)象鎖來(lái)實(shí)現(xiàn)的,因?yàn)樵陬?lèi)加載的時(shí)候,JVM會(huì)為每一個(gè)類(lèi)創(chuàng)建一個(gè)java.lang.Class的一個(gè)實(shí)例;所以當(dāng)鎖對(duì)對(duì)象的時(shí)候,也就鎖住這個(gè)類(lèi)的類(lèi)對(duì)象。
 
另外,一個(gè)線程是可以對(duì)一個(gè)對(duì)象進(jìn)行多次上鎖,也就對(duì)應(yīng)著多次釋放;它是通過(guò)JVM為每個(gè)對(duì)象鎖提供的lock計(jì)算器,上一次鎖,就加1,對(duì)應(yīng)的減1,當(dāng)計(jì)算器的值為0時(shí),就釋放。這個(gè)對(duì)象鎖是JVM內(nèi)部的監(jiān)視器使用的,也是由JVM自動(dòng)生成的,所有程序猿就不用自己動(dòng)手來(lái)加了。
 
介紹完java的同步原理后,我們進(jìn)入正題,先來(lái)說(shuō)說(shuō)synchronized的使用,而其它的同步,將在后面的章節(jié)中介紹。
 
先來(lái)運(yùn)行一個(gè)例子試試。

package thread_test; 
 
/** 
 * 測(cè)試擴(kuò)展Thread類(lèi)實(shí)現(xiàn)的多線程程序 
 * 
 */ 
public class TestThread extends Thread{  
  private int threadnum; 
 
  public TestThread(int threadnum) {  
    this.threadnum = threadnum;  
  } 
   
  @Override 
  public synchronized void run() {  
    for(int i = 0;i<1000;i++){  
          System.out.println("NO." + threadnum + ":" + i ); 
    } 
    }  
   
    public static void main(String[] args) throws Exception {  
      for(int i=0; i<10; i++){ 
          new TestThread(i).start(); 
          Thread.sleep(1); 
      } 
    }  
} 

 
運(yùn)行結(jié)果:

NO.0:887 
NO.0:888 
NO.0:889 
NO.0:890 
NO.0:891 
NO.0:892 
NO.0:893 
NO.0:894 
NO.7:122 
NO.7:123 
NO.7:124 

上面只是一個(gè)片段,說(shuō)明一個(gè)問(wèn)題而已。
細(xì)心的童鞋會(huì)發(fā)現(xiàn),NO.0:894后面是NO.7:122,也就是說(shuō)沒(méi)有按照從0開(kāi)始到999。
都說(shuō)synchronized可以實(shí)現(xiàn)同步方法或同步塊,這里怎么就不行呢?
 
先從同步的機(jī)制來(lái)分析一下,同步是通過(guò)鎖來(lái)實(shí)現(xiàn)的,那么上面的例子中,鎖定了什么對(duì)象,或鎖定了什么類(lèi)呢?里面有兩個(gè)變量,一個(gè)是i,一個(gè)是threadnum;i是方法內(nèi)部的,threadnum是私有的。
再來(lái)了解一下synchronized的運(yùn)行機(jī)制:
      在java程序中,當(dāng)使用synchronized塊或synchronized方法時(shí),標(biāo)志這個(gè)區(qū)域進(jìn)行監(jiān)視;而JVM在處理程序時(shí),當(dāng)有程序進(jìn)入監(jiān)視區(qū)域時(shí),就會(huì)自動(dòng)鎖上對(duì)象或類(lèi)。
 
那么上面的例子中,synchronized關(guān)鍵字用上后,鎖定的是什么呢?
當(dāng)synchronized方法時(shí),鎖定調(diào)用方法的實(shí)例對(duì)象本身做為對(duì)象鎖。本例中,10個(gè)線程都有自己創(chuàng)建的TestThread的類(lèi)對(duì)象,所以獲取的對(duì)象鎖,也是自己的對(duì)象鎖,與其它線程沒(méi)有任何關(guān)系。
 
要實(shí)現(xiàn)方法鎖定,必須鎖定有共享的對(duì)象。
 
對(duì)上面的實(shí)例修改一下,再看看:

package thread_test; 
 
/** 
 * 測(cè)試擴(kuò)展Thread類(lèi)實(shí)現(xiàn)的多線程程序 
 * 
 */ 
public class TestThread extends Thread{  
  private int threadnum; 
  private String flag;  //標(biāo)記 
   
  public TestThread(int threadnum,String flag) {  
       this.threadnum = threadnum;  
        this.flag = flag; 
    } 
   
  @Override 
    public void run() {  
    synchronized(flag){ 
      for(int i = 0;i<1000;i++){  
              System.out.println("NO." + threadnum + ":" + i ); 
          }  
    } 
    }  
 
    public static void main(String[] args) throws Exception {  
      String flag = new String("flag"); 
      for(int i=0; i<10; i++){ 
          new TestThread(i,flag).start(); 
          Thread.sleep(1); 
      } 
    }  
} 

 
也就加了一個(gè)共享的標(biāo)志flag。然后在通過(guò)synchronized塊,對(duì)flag標(biāo)志進(jìn)行同步;這就滿足了鎖定共享對(duì)象的條件。
是的,運(yùn)行結(jié)果,已經(jīng)按順序來(lái)了。

通過(guò)synchronized塊,指定獲取對(duì)象鎖來(lái)達(dá)到同步的目的。那有沒(méi)有其它的方法,可以通過(guò)synchronized方法來(lái)實(shí)現(xiàn)呢?
 
根據(jù)同步的原理:如果能獲取一個(gè)共享對(duì)象鎖或類(lèi)鎖,及可實(shí)現(xiàn)同步。那么我們是不是可以通過(guò)共享一個(gè)類(lèi)鎖來(lái)實(shí)現(xiàn)呢?
 
是的,我們可以使用靜態(tài)同步方法,根據(jù)靜態(tài)方法的特性,它只允許類(lèi)對(duì)象本身才可以調(diào)用,不能通過(guò)實(shí)例化一個(gè)類(lèi)對(duì)象來(lái)調(diào)用。那么如果獲得了這個(gè)靜態(tài)方法的鎖,也就是獲得這個(gè)類(lèi)鎖,而這個(gè)類(lèi)鎖都是TestThread類(lèi)鎖,及達(dá)到了獲取共享類(lèi)鎖的目的。
 
實(shí)現(xiàn)代碼如下:

package thread_test; 
 
/** 
 * 測(cè)試擴(kuò)展Thread類(lèi)實(shí)現(xiàn)的多線程程序 
 * 
 * @author ciding 
 * @createTime Dec 7, 2011 9:37:25 AM 
 * 
 */ 
public class TestThread extends Thread{  
  private int threadnum; 
   
  public TestThread(int threadnum) {  
    this.threadnum = threadnum;  
  } 
   
  public static synchronized void staticTest(int threadnum) {  
    for(int i = 0;i<1000;i++){  
      System.out.println("NO." + threadnum + ":" + i ); 
    }  
  }  
 
  public static void main(String[] args) throws Exception {  
    for(int i=0; i<10; i++){ 
      new TestThread(i).start(); 
      Thread.sleep(1); 
    } 
  }  
   
  @Override 
  public void run(){ 
    staticTest(threadnum); 
  } 
} 

 運(yùn)行結(jié)果略,與第二個(gè)例子中一樣。
 
 
以上的內(nèi)容主要是說(shuō)明兩個(gè)問(wèn)題:同步塊與同步方法。
1,同步塊:獲取的對(duì)象鎖是synchronized(flag)中的flag對(duì)象鎖。
2,同步方法:獲取的是方法所屬的類(lèi)對(duì)象,及類(lèi)對(duì)象鎖。
靜態(tài)同步方法,由于多個(gè)線程都會(huì)共享,所以一定會(huì)同步。
而非靜態(tài)同步方法,只有在單例模式下才會(huì)同步。

相關(guān)文章

  • Java webSerivce的使用看完你就明白了

    Java webSerivce的使用看完你就明白了

    因?yàn)榍岸螘r(shí)間,需要使用到webService來(lái)調(diào)用公司的其他系統(tǒng)api接口,但是請(qǐng)求方式和我熟知的http請(qǐng)求不一樣,是基于soap協(xié)議來(lái)傳輸xml數(shù)據(jù)格式,請(qǐng)求的參數(shù)極其復(fù)雜,需要封裝多層xml數(shù)據(jù)格式,并且我不知道對(duì)方的api接口是什么語(yǔ)言,甚至不知道他們存在于什么平臺(tái)
    2022-03-03
  • Springboot使用put、delete請(qǐng)求報(bào)錯(cuò)405的處理

    Springboot使用put、delete請(qǐng)求報(bào)錯(cuò)405的處理

    這篇文章主要介紹了Springboot使用put、delete請(qǐng)求報(bào)錯(cuò)405的處理方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • idea中springboot整合mybatis找不到mapper接口的原因分析

    idea中springboot整合mybatis找不到mapper接口的原因分析

    這篇文章主要介紹了idea中springboot整合mybatis找不到mapper接口的原因分析及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java字符串split使用方法代碼實(shí)例

    Java字符串split使用方法代碼實(shí)例

    這篇文章主要介紹了Java字符串split使用方法代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 談?wù)剬?duì)Java中的volatile的理解

    談?wù)剬?duì)Java中的volatile的理解

    這篇文章主要介紹了對(duì)Java中的volatile的理解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Java實(shí)現(xiàn)ATM系統(tǒng)超全面步驟解讀建議收藏

    Java實(shí)現(xiàn)ATM系統(tǒng)超全面步驟解讀建議收藏

    這篇文章主要為大家詳細(xì)介紹了用Java實(shí)現(xiàn)簡(jiǎn)單ATM機(jī)功能,文中實(shí)現(xiàn)流程寫(xiě)的非常清晰全面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java在PDF中添加表格過(guò)程詳解

    Java在PDF中添加表格過(guò)程詳解

    這篇文章主要介紹了Java在PDF中添加表格過(guò)程詳解,本文將介紹通過(guò)Java編程在PDF文檔中添加表格的方法。添加表格時(shí),可設(shè)置表格邊框、單元格對(duì)齊方式、單元格背景色、單元格合并、插入圖片、設(shè)置行高、列寬、字體、字號(hào)等,需要的朋友可以參考下
    2019-07-07
  • Mybatis?sql與xml文件讀取方法詳細(xì)分析

    Mybatis?sql與xml文件讀取方法詳細(xì)分析

    這篇文章主要介紹了Mybatis?sql與xml文件讀取方法,在執(zhí)行一個(gè)自定義sql語(yǔ)句時(shí),dao對(duì)應(yīng)的代理對(duì)象時(shí)如何找到sql,也就是dao的代理對(duì)象和sql之間的關(guān)聯(lián)關(guān)系是如何建立的
    2023-01-01
  • java使用Filter實(shí)現(xiàn)自動(dòng)登錄的方法

    java使用Filter實(shí)現(xiàn)自動(dòng)登錄的方法

    這篇文章主要為大家詳細(xì)介紹了java使用Filter實(shí)現(xiàn)自動(dòng)登錄的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java設(shè)置httponly?cookie的實(shí)現(xiàn)示例

    Java設(shè)置httponly?cookie的實(shí)現(xiàn)示例

    本文主要介紹了Java設(shè)置httponly?cookie的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08

最新評(píng)論