中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java多線程編程中的鎖有什么用

發布時間:2021-08-30 11:14:23 來源:億速云 閱讀:189 作者:chen 欄目:編程語言

這篇文章主要講解了“Java多線程編程中的鎖有什么用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java多線程編程中的鎖有什么用”吧!

閱讀目錄

一、盡量不要鎖住方法

二、縮小同步代碼塊,只鎖數據

三、鎖中盡量不要再包含鎖

四、將鎖私有化,在內部管理鎖

五、進行適當的鎖分解

正文

并發環境下進行編程時,需要使用鎖機制來同步多線程間的操作,保證共享資源的互斥訪問。加鎖會帶來性能上的損壞,似乎是眾所周知的事情。然而,加鎖本身不會帶來多少的性能消耗,性能主要是在線程的獲取鎖的過程。

如果只有一個線程競爭鎖,此時并不存在多線程競爭的情況,那么JVM會進行優化,那么這時加鎖帶來的性能消耗基本可以忽略。因此,規范加鎖的操作,優化鎖的使用方法,避免不必要的線程競爭,不僅可以提高程序性能,也能避免不規范加鎖可能造成線程死鎖問題,提高程序健壯性。下面闡述幾種鎖優化的思路。

一、盡量不要鎖住方法

在普通成員函數上加鎖時,線程獲得的是該方法所在對象的對象鎖。此時整個對象都會被鎖住。這也意味著,如果這個對象提供的多個同步方法是針對不同業務的,那么由于整個對象被鎖住,一個業務業務在處理時,其他不相關的業務線程也必須wait。下面的例子展示了這種情況:

LockMethod類包含兩個同步方法,分別在兩種業務處理中被調用:

public class LockMethod   {     public synchronized void busiA() {         for (int i = 0; i < 10000; i++) {             System.out.println(Thread.currentThread().getName() + "deal with bussiness A:"+i);         }     }     public synchronized void busiB() {         for (int i = 0; i < 10000; i++) {             System.out.println(Thread.currentThread().getName() + "deal with bussiness B:"+i);         }     } }

BUSSA是線程類,用來處理A業務,調用的是LockMethod的busiA()方法:

public class BUSSA extends Thread {     LockMethod lockMethod;     void deal(LockMethod lockMethod){         this.lockMethod = lockMethod;     }      @Override     public void run() {         super.run();         lockMethod.busiA();     } }

BUSSB是線程類,用來處理B業務,調用的是LockMethod的busiB()方法:

public class BUSSB extends Thread {     LockMethod lockMethod;     void deal(LockMethod lockMethod){         this.lockMethod = lockMethod;     }      @Override     public void run() {         super.run();         lockMethod.busiB();     } }

TestLockMethod類,使用線程BUSSA與BUSSB進行業務處理:

public class TestLockMethod extends Thread {      public static void main(String[] args) {         LockMethod lockMethod = new LockMethod();         BUSSA bussa = new BUSSA();         BUSSB bussb = new BUSSB();         bussa.deal(lockMethod);         bussb.deal(lockMethod);         bussa.start();         bussb.start();      } } 運行程

運行程序,可以看到在線程bussa 執行的過程中,bussb是不能夠進入函數 busiB()的,因為此時lockMethod  的對象鎖被線程bussa獲取了。

二、縮小同步代碼塊,只鎖數據

有時候為了編程方便,有些人會synchnoized很大的一塊代碼,如果這個代碼塊中的某些操作與共享資源并不相關,那么應當把它們放到同步塊外部,避免長時間的持有鎖,造成其他線程一直處于等待狀態。尤其是一些循環操作、同步I/O操作。

不止是在代碼的行數范圍上縮小同步塊,在執行邏輯上,也應該縮小同步塊,例如多加一些條件判斷,符合條件的再進行同步,而不是同步之后再進行條件判斷,盡量減少不必要的進入同步塊的邏輯。

三、鎖中盡量不要再包含鎖

這種情況經常發生,線程在得到了A鎖之后,在同步方法塊中調用了另外對象的同步方法,獲得了第二個鎖,這樣可能導致一個調用堆棧中有多把鎖的請求,多線程情況下可能會出現很復雜、難以分析的異常情況,導致死鎖的發生。下面的代碼顯示了這種情況:

synchronized(A){     synchronized(B){        }   }

或是在同步塊中調用了同步方法:

synchronized(A){      B  b = objArrayList.get(0);     b.method(); //這是一個同步方法 }

解決的辦法是跳出來加鎖,不要包含加鎖:

{      B b = null;   synchronized(A){     b = objArrayList.get(0);   }   b.method(); }

四、將鎖私有化,在內部管理鎖

把鎖作為一個私有的對象,外部不能拿到這個對象,更安全一些。對象可能被其他線程直接進行加鎖操作,此時線程便持有了該對象的對象鎖,例如下面這種情況:

class A {     public void method1() {     } }  class B {     public void method1() {         A a = new A();         synchronized (a) { //直接進行加鎖 a.method1();          }     } }

這種使用方式下,對象a的對象鎖被外部所持有,讓這把鎖在外部多個地方被使用是比較危險的,對代碼的邏輯流程閱讀也造成困擾。一種更好的方式是在類的內部自己管理鎖,外部需要同步方案時,也是通過接口方式來提供同步操作:

class A {     private Object lock = new Object();     public void method1() {         synchronized (lock){          }     } }  class B {     public void method1() {         A a = new A();         a.method1();     } }

五、進行適當的鎖分解

考慮下面這段程序:

public class GameServer {   public Map<String, List<Player>> tables = new HashMap<String, List<Player>>();    public void join(Player player, Table table) {     if (player.getAccountBalance() > table.getLimit()) {       synchronized (tables) {         List<Player> tablePlayers = tables.get(table.getId());         if (tablePlayers.size() < 9) {           tablePlayers.add(player);         }       }     }   }   public void leave(Player player, Table table) {/*省略*/}    public void createTable() {/*省略*/}    public void destroyTable(Table table) {/*省略*/} }

在這個例子中,join方法只使用一個同步鎖,來獲取tables中的List對象,然后判斷玩家數量是不是小于9,如果是,就調增加一個玩家。當有成千上萬個List存在tables中時,對tables鎖的競爭將非常激烈。

在這里,我們可以考慮進行鎖的分解:快速取出數據之后,對List對象進行加鎖,讓其他線程可快速競爭獲得tables對象鎖:

public class GameServer {   public Map<String, List<Player>> tables = new HashMap<String, List<Player>>();    public void join(Player player, Table table) {     if (player.getAccountBalance() > table.getLimit()) {       List<Player> tablePlayers = null;       synchronized (tables) {           tablePlayers = tables.get(table.getId());       }        synchronized (tablePlayers) {         if (tablePlayers.size() < 9) {           tablePlayers.add(player);         }       }     }   }   public void leave(Player player, Table table) {/*省略*/}   public void createTable() {/*省略*/}   public void destroyTable(Table table) {/*省略*/} }

感謝各位的閱讀,以上就是“Java多線程編程中的鎖有什么用”的內容了,經過本文的學習后,相信大家對Java多線程編程中的鎖有什么用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿拉善盟| 蒙自县| 特克斯县| 潍坊市| 合川市| 六枝特区| 万年县| 台东市| 化德县| 巍山| 岳阳市| 龙游县| 长子县| 棋牌| 资讯| 汨罗市| 肥东县| 子洲县| 桐城市| 托克逊县| 余庆县| 沧源| 观塘区| 诏安县| 梧州市| 泸溪县| 无极县| 佳木斯市| 靖江市| 沛县| 梅河口市| 扎赉特旗| 永和县| 布尔津县| 娱乐| 新竹市| 金沙县| 海盐县| 谢通门县| 荣成市| 屯门区|