程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> java並發之synchronized

java並發之synchronized

編輯:JAVA綜合教程

java並發之synchronized


在Java中,每一個對象都擁有一個鎖標記(monitor),也稱為監視器,多線程同時訪問某個對象時,線程只有獲取了該對象的鎖才能訪問。

  在Java中,可以使用synchronized關鍵字來標記一個方法或者代碼塊,當某個線程調用該對象的synchronized方法或者訪問synchronized代碼塊時,這個線程便獲得了該對象的鎖,其他線程暫時無法訪問這個方法,只有等待這個方法執行完畢或者代碼塊執行完畢,這個線程才會釋放該對象的鎖,其他線程才能執行這個方法或者代碼塊。

注意:

1)當一個線程正在訪問一個對象的synchronized方法,那麼其他線程不能訪問該對象的其他synchronized方法。這個原因很簡單,因為一個對象只有一把鎖,當一個線程獲取了該對象的鎖之後,其他線程無法獲取該對象的鎖,所以無法訪問該對象的其他synchronized方法。

2)當一個線程正在訪問一個對象的synchronized方法,那麼其他線程能訪問該對象的非synchronized方法。這個原因很簡單,訪問非synchronized方法不需要獲得該對象的鎖,假如一個方法沒用synchronized關鍵字修飾,說明它不會使用到臨界資源,那麼其他線程是可以訪問這個方法的

3)如果一個線程A需要訪問對象object1的synchronized方法fun1,另外一個線程B需要訪問對象object2的synchronized方法fun1,即使object1和object2是同一類型),也不會產生線程安全問題,因為他們訪問的是不同的對象,所以不存在互斥問題。

 

synchronized代碼塊使用起來比synchronized方法要靈活得多。因為也許一個方法中只有一部分代碼只需要同步,如果此時對整個方法用synchronized進行同步,會影響程序執行效率。而使用synchronized代碼塊就可以避免這個問題,synchronized代碼塊可以實現只對需要同步的地方進行同步。另外,每個類也會有一個鎖,它可以用來控制對static數據成員的並發訪問。並且如果一個線程執行一個對象的非static synchronized方法,另外一個線程需要執行這個對象所屬類的static synchronized方法,此時不會發生互斥現象,因為訪問static synchronized方法占用的是類鎖,而訪問非static synchronized方法占用的是對象鎖,所以不存在互斥現象。

 

[java]view plaincopy   在CODE上查看代碼片派生到我的代碼片
  1. publicclassTest{
  2.  
  3. publicstaticvoidmain(String[]args){
  4. finalInsertDatainsertData=newInsertData();
  5. newThread(){
  6. @Override
  7. publicvoidrun(){
  8. insertData.insert();
  9. }
  10. }.start();
  11. newThread(){
  12. @Override
  13. publicvoidrun(){
  14. insertData.insert1();
  15. }
  16. }.start();
  17. }
  18. }
  19.  
  20. classInsertData{
  21. publicsynchronizedvoidinsert(){
  22. System.out.println("執行insert");
  23. try{
  24. Thread.sleep(5000);
  25. }catch(InterruptedExceptione){
  26. e.printStackTrace();
  27. }
  28. System.out.println("執行insert完畢");
  29. }
  30.  
  31. publicsynchronizedstaticvoidinsert1(){
  32. System.out.println("執行insert1");
  33. System.out.println("執行insert1完畢");
  34. }
  35. } 結果:

     

    執行insert

    執行insert1

    執行insert1完畢

    執行insert完畢

     

    第一個線程裡面執行的是insert方法,不會導致第二個線程執行insert1方法發生阻塞現象。

      下面我們看一下synchronized關鍵字到底做了什麼事情,我們來反編譯它的字節碼看一下,下面這段代碼反編譯後的字節碼為:

     

    [java]view plaincopy   在CODE上查看代碼片派生到我的代碼片
    1. publicclassInsertData{
    2. privateObjectobject=newObject();
    3.  
    4. publicvoidinsert(Threadthread){
    5. synchronized(object){
    6.  
    7. }
    8. }
    9.  
    10. publicsynchronizedvoidinsert1(Threadthread){
    11.  
    12. }
    13.  
    14. publicvoidinsert2(Threadthread){
    15.  
    16. }
}

[java]view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. classFooimplementsRunnable
  2. {
  3. privatebyte[]lock=newbyte[0];//特殊的instance變量
  4. PublicvoidmethodA()
  5. {
  6. synchronized(lock){//…}
  7. }
  8. //…..
}將synchronized作用於static 函數,示例代碼如下:[java]view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. ClassFoo
  2. {
  3. publicsynchronizedstaticvoidmethodAAA()//同步的static函數
  4. {
  5. //….
  6. }
  7. publicvoidmethodBBB()
  8. {
  9. synchronized(Foo.class)//classliteral(類名稱字面常量)
  10. }
} 代碼中的methodBBB()方法是把class literal作為鎖的情況,它和同步的static函數產生的效果是一樣的,取得的鎖很特別,是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。
synchronized的缺陷:
  1)獲取鎖的線程執行完了該代碼塊,然後線程釋放對鎖的占有;
  但是采用synchronized關鍵字來實現同步的話,就會導致一個問題:
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved