最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java synchronized關(guān)鍵字的用法

 更新時間:2016年05月03日 10:15:59   投稿:wulei  
synchronized關(guān)鍵字我們大家都知道是線程同步關(guān)鍵字.總結(jié)一下日常的使用方法,還有一個坑.

0.先導(dǎo)的問題代碼

    下面的代碼演示了一個計數(shù)器,兩個線程同時對i進行累加的操作,各執(zhí)行1000000次.我們期望的結(jié)果肯定是i=2000000.但是我們多次執(zhí)行以后,會發(fā)現(xiàn)i的值永遠小于2000000.這是因為,兩個線程同時對i進行寫入的時候,其中一個線程的結(jié)果會覆蓋另外一個.

public class AccountingSync implements Runnable {
  static int i = 0;
  public void increase() {
    i++;
  }
 
  @Override
  public void run() {
    for (int j = 0; j < 1000000; j++) {
      increase();
    }
  }
 
  public static void main(String[] args) throws InterruptedException {
    AccountingSync accountingSync = new AccountingSync();
 
    Thread t1 = new Thread(accountingSync);
    Thread t2 = new Thread(accountingSync);
 
    t1.start();
    t2.start();
 
    t1.join();
    t2.join();
 
    System.out.println(i);
  }
}

    要從根本上解決這個問題,我們必須保證多個線程在對i進行操作的時候,要完全的同步.也就是說到A線程對i進行寫入的時候,B線程不僅不可以寫入,連讀取都不可以.

1.synchronized關(guān)鍵字的作用

    關(guān)鍵字synchronized的作用其實就是實現(xiàn)線程間的同步.它的工作就是對同步的代碼進行加鎖,使得每一次,只能有一個線程進入同步塊,從而保證線程間的安全性.就像上面的代碼中,i++的操作只能同時又一個線程在執(zhí)行.

2.synchronized關(guān)鍵字的用法

指定對象加鎖:對給定的對象進行加鎖,進入同步代碼塊要獲得給定對象的鎖

直接作用于實例方法:相當(dāng)于對當(dāng)前實例加鎖,進入同步代碼塊要獲得當(dāng)前實例的鎖(這要求創(chuàng)建Thread的時候,要用同一個Runnable的實例才可以)

直接作用于靜態(tài)方法:相當(dāng)于給當(dāng)前類加鎖,進入同步代碼塊前要獲得當(dāng)前類的鎖

2.1指定對象加鎖

    下面的代碼,將synchronized作用于一個給定的對象.這里有一個注意的,給定對象一定要是static的,否則我們每次new一個線程出來,彼此并不共享該對象,加鎖的意義也就不存在了.

public class AccountingSync implements Runnable {
  final static Object OBJECT = new Object();
 
  static int i = 0;
  public void increase() {
    i++;
  }
 
  @Override
  public void run() {
    for (int j = 0; j < 1000000; j++) {
      synchronized (OBJECT) {
        increase();
      }
    }
  }
 
  public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(new AccountingSync());
    Thread t2 = new Thread(new AccountingSync());
 
    t1.start();
    t2.start();
 
    t1.join();
    t2.join();
 
    System.out.println(i);
  }
}
2.2直接作用于實例方法

    synchronized關(guān)鍵字作用于實例方法,就是說在進入increase()方法之前,線程必須獲得當(dāng)前實例的鎖.這就要求我們,在創(chuàng)建Thread實例的時候,要使用同一個Runnable的對象實例.否則,線程的鎖都不在同一個實例上面,無從去談加鎖/同步的問題了.

public class AccountingSync implements Runnable {
  static int i = 0;
  public synchronized void increase() {
    i++;
  }
 
  @Override
  public void run() {
    for (int j = 0; j < 1000000; j++) {
      increase();
    }
  }
 
  public static void main(String[] args) throws InterruptedException {
    AccountingSync accountingSync = new AccountingSync();
 
    Thread t1 = new Thread(accountingSync);
    Thread t2 = new Thread(accountingSync);
 
    t1.start();
    t2.start();
 
    t1.join();
    t2.join();
 
    System.out.println(i);
  }
}

    請注意main方法的前三行,說明關(guān)鍵字作用于實例方法上的正確用法.

2.3直接作用于靜態(tài)方法

    將synchronized關(guān)鍵字作用在static方法上,就不用像上面的例子中,兩個線程要指向同一個Runnable方法.因為方法塊需要請求的是當(dāng)前類的鎖,而不是當(dāng)前實例,線程間還是可以正確同步的.

public class AccountingSync implements Runnable {
  static int i = 0;
  public static synchronized void increase() {
    i++;
  }
 
  @Override
  public void run() {
    for (int j = 0; j < 1000000; j++) {
      increase();
    }
  }
 
  public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(new AccountingSync());
    Thread t2 = new Thread(new AccountingSync());
 
    t1.start();
    t2.start();
 
    t1.join();
    t2.join();
 
    System.out.println(i);
  }
}

3.錯誤的加鎖

    從上面的例子里,我們知道,如果我們需要一個計數(shù)器應(yīng)用,為了保證數(shù)據(jù)的正確性,我們自然會需要對計數(shù)器加鎖,因此,我們可能會寫出下面的代碼:

public class BadLockOnInteger implements Runnable {
  static Integer i = 0;
  @Override
  public void run() {
    for (int j = 0; j < 1000000; j++) {
      synchronized (i) {
        i++;
      }
    }
  }
 
  public static void main(String[] args) throws InterruptedException {
    BadLockOnInteger badLockOnInteger = new BadLockOnInteger();
 
    Thread t1 = new Thread(badLockOnInteger);
    Thread t2 = new Thread(badLockOnInteger);
 
    t1.start();
    t2.start();
 
    t1.join();
    t2.join();
 
    System.out.println(i);
  }
}

    當(dāng)我們運行上面代碼的時候,會發(fā)現(xiàn)輸出的i很小.這說明線程并沒有安全.

    要解釋這個問題,要從Integer說起:在Java中,Integer屬于不變對象,和String一樣,對象一旦被創(chuàng)建,就不能被修改了.如果你有一個Integer=1,那么它就永遠都是1.如果你想讓這個對象=2呢?只能重新創(chuàng)建一個Integer.每次i++之后,相當(dāng)于調(diào)用了Integer的valueOf方法,我們看一下Integer的valueOf方法的源碼:

public static Integer valueOf(int i) {
  if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
  return new Integer(i);
}

    Integer.valueOf()實際上是一個工廠方法,他會傾向于返回一個新的Integer對象,并把值重新復(fù)制給i;

    所以,我們就知道問題所在的原因,由于在多個線程之間,由于i++之后,i都指向了一個新的對象,所以線程每次加鎖可能都加載了不同的對象實例上面.解決方法很簡單,使用上面的3種synchronize的方法之一就可以解決了.

相關(guān)文章

  • Java實現(xiàn)AWT四大事件的詳細過程

    Java實現(xiàn)AWT四大事件的詳細過程

    AWT的事件處理是一種委派式事件處理方式:普通組件(事件源)將整個事件處理委托給特定的對象(事件監(jiān)聽器);當(dāng)該事件源發(fā)生指定的事件時,就通知所委托的事件監(jiān)聽器,由事件監(jiān)聽器來處理這個事件
    2022-04-04
  • SpringBoot實現(xiàn)日志鏈路追蹤的項目實踐

    SpringBoot實現(xiàn)日志鏈路追蹤的項目實踐

    在分布式系統(tǒng)中,由于請求的處理過程可能會跨越多個服務(wù),因此,對請求的追蹤變得尤為重要,本文主要介紹了SpringBoot實現(xiàn)日志鏈路追蹤的項目實踐,感興趣的可以了解一下
    2024-03-03
  • 零基礎(chǔ)寫Java知乎爬蟲之將抓取的內(nèi)容存儲到本地

    零基礎(chǔ)寫Java知乎爬蟲之將抓取的內(nèi)容存儲到本地

    上一回我們說到了如何把知乎的某些內(nèi)容爬取出來,那么這一回我們就說說怎么把這些內(nèi)容存儲到本地吧。
    2014-11-11
  • java多線程之Balking模式介紹

    java多線程之Balking模式介紹

    大家好,本篇文章主要講的是java多線程之Balking模式介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • java easyPOI實現(xiàn)導(dǎo)出一對多數(shù)據(jù)

    java easyPOI實現(xiàn)導(dǎo)出一對多數(shù)據(jù)

    這篇文章主要為大家詳細介紹了java如何利用easyPOI實現(xiàn)導(dǎo)出一對多數(shù)據(jù),并且可以設(shè)置邊框、字體和字體大小,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • 關(guān)于IDEA配置文件字符集的問題

    關(guān)于IDEA配置文件字符集的問題

    這篇文章主要介紹了關(guān)于IDEA配置文件字符集的問題,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Spring cloud gateway設(shè)置context-path服務(wù)路由404排查過程

    Spring cloud gateway設(shè)置context-path服務(wù)路由404排查過程

    這篇文章主要介紹了Spring cloud gateway設(shè)置context-path服務(wù)路由404排查過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • git stash 和unstash的使用操作,git unstash failed

    git stash 和unstash的使用操作,git unstash failed

    這篇文章主要介紹了git stash 和unstash的使用操作,git unstash failed,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • IDEA創(chuàng)建javaee項目依賴war exploded變紅失效的解決方案

    IDEA創(chuàng)建javaee項目依賴war exploded變紅失效的解決方案

    在使用IntelliJ IDEA創(chuàng)建JavaEE項目時,可能會遇到Tomcat部署的warexploded文件出現(xiàn)問題,解決方法是首先刪除有問題的warexploded依賴,然后根據(jù)圖示重新導(dǎo)入項目,此外,調(diào)整虛擬路徑有時也能有效解決問題
    2024-09-09
  • java測試框架的方法

    java測試框架的方法

    這篇文章主要介紹了java測試框架的方法,文中代碼非常詳細,供大家學(xué)習(xí)和參考,感興趣的朋友可以了解下
    2020-06-06

最新評論

钦州市| 梁平县| 恭城| 科技| 奈曼旗| 额济纳旗| 高阳县| 磴口县| 霞浦县| 吴忠市| 大邑县| 灵山县| 台江县| 麻江县| 大庆市| 新源县| 井研县| 紫金县| 鹤庆县| 绥阳县| 海南省| 新邵县| 木里| 南昌县| 临清市| 甘谷县| 洛扎县| 宁蒗| 通城县| 天津市| 商城县| 清原| 清镇市| 景谷| 平邑县| 广河县| 彭泽县| 枝江市| 门头沟区| 武定县| 凤庆县|