日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java锁性能对比_提高Java的锁性能

發(fā)布時間:2023/12/3 java 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java锁性能对比_提高Java的锁性能 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java鎖性能對比

Plumbr是唯一可以通過解釋應(yīng)用程序性能數(shù)據(jù)來自動檢測Java性能問題根本原因的解決方案。

幾個月前,我們在Plumbr中引入了鎖定線程檢測之后,我們開始收到類似于“嘿,太好了,現(xiàn)在我知道是什么導(dǎo)致了性能問題,但是現(xiàn)在應(yīng)該做什么?”這樣的查詢。

我們正在努力將解決方案說明構(gòu)建到我們自己的產(chǎn)品中,但是在這篇文章中,我將分享一些可以獨立于用于檢測鎖的工具應(yīng)用的常見技術(shù)。 這些方法包括鎖拆分,并發(fā)數(shù)據(jù)結(jié)構(gòu),保護數(shù)據(jù)(而不是代碼)和減少鎖范圍。

鎖不是邪惡的,鎖爭用是

每當您遇到線程代碼的性能問題時,就有機會開始指責鎖。 畢竟,常見的“知識”是鎖很慢并且限制了可伸縮性。 因此,如果您具備了這種“知識”并開始優(yōu)化代碼并擺脫了鎖,那么您最終有可能引入令人討厭的并發(fā)錯誤,這些錯誤將在以后出現(xiàn)。

因此,了解競爭鎖和非競爭鎖之間的區(qū)別非常重要。 當一個線程試圖進入另一個線程當前執(zhí)行的同步塊/方法時,發(fā)生鎖爭用。 現(xiàn)在,第二個線程被迫等待,直到第一個線程完成了執(zhí)行同步塊并釋放監(jiān)視器為止。 當一次僅一個線程試圖執(zhí)行同步代碼時,鎖保持無競爭狀態(tài)。

實際上,JVM中的同步針對無競爭的情況進行了優(yōu)化,并且對于絕大多數(shù)應(yīng)用程序而言,無競爭的鎖幾乎在執(zhí)行期間沒有開銷。 因此,它不是性能應(yīng)歸咎的鎖,而是爭執(zhí)的鎖。 有了這些知識,讓我們看看如何減少爭用的可能性或減少爭用的時間。

保護數(shù)據(jù)而不是代碼

實現(xiàn)線程安全的一種快速方法是鎖定對整個方法的訪問。 例如,請看以下示例,該示例說明了構(gòu)建在線撲克服務(wù)器的幼稚嘗試:

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

作者的初衷是好的–當新玩家加入桌臺時,必須保證坐在桌旁的玩家人數(shù)不會超過9人。

但是,只要這樣的解決方案實際上負責使玩家坐在桌子上(即使是在流量適中的撲克場所),該系統(tǒng)注定要通過等待釋放鎖的線程不斷觸發(fā)爭用事件。 鎖定塊包含帳戶余額和表限制檢查,這可能會涉及昂貴的操作,從而增加爭用的可能性和持續(xù)時間。

解決方案的第一步是通過將同步從方法聲明移到方法主體,確保我們保護數(shù)據(jù),而不是代碼。 在上面的簡約示例中,它可能一開始并沒有太大變化。 但是讓我們考慮整個GameServer接口,而不僅僅是單個join()方法:

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

原本似乎是次要的變化,現(xiàn)在影響了整個班級的行為。 每當玩家加入表時,先前同步的方法就會鎖定在GameServer實例( this )上,并向試圖同時離開 table ()表的玩家引入競爭事件。 將鎖從方法簽名移到方法主體可推遲鎖定并減少爭用可能性。

縮小鎖定范圍

現(xiàn)在,在確保它是我們實際保護的數(shù)據(jù)而不是代碼之后,我們應(yīng)該確保我們的解決方案僅鎖定必要的內(nèi)容,例如,當上面的代碼如下重寫時:

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);}}}}//other methods skipped for brevity }

那么檢查玩家?guī)粲囝~的潛在耗時操作(可能涉及IO操作)現(xiàn)在已超出鎖定范圍。 注意,引入該鎖僅是為了防止超出表的容量,并且?guī)粲囝~檢查也不是該保護措施的一部分。

開鎖

當我們看最后一個代碼示例時,您可以清楚地注意到整個數(shù)據(jù)結(jié)構(gòu)都受同一鎖保護。 考慮到我們可能在這種結(jié)構(gòu)中容納成千上萬張撲克桌,由于我們必須分別保護每張桌子以防容量溢出,因此它仍然會帶來爭用事件的高風險。

為此,有一種簡單的方法可以在每個表中引入單個鎖,例如以下示例:

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 = tables.get(table.getId());synchronized (tablePlayers) {if (tablePlayers.size() < 9) {tablePlayers.add(player);}}}}//other methods skipped for brevity }

現(xiàn)在,如果我們僅同步訪問同一表而不是所有表的訪問 ,則可以大大降低鎖爭用的可能性。 例如,在我們的數(shù)據(jù)結(jié)構(gòu)中有100個表,爭用的可能性現(xiàn)在比以前小100倍。

使用并發(fā)數(shù)據(jù)結(jié)構(gòu)

另一個改進是刪除傳統(tǒng)的單線程數(shù)據(jù)結(jié)構(gòu),并使用為并行使用而明確設(shè)計的數(shù)據(jù)結(jié)構(gòu)。 例如,當選擇ConcurrentHashMap來存儲所有撲克表時,將導(dǎo)致類似于以下代碼:

public class GameServer {public Map<String, List<Player>> tables = new ConcurrentHashMap<String, List<Player>>();public synchronized void join(Player player, Table table) {/*Method body skipped for brevity*/}public synchronized void leave(Player player, Table table) {/*Method body skipped for brevity*/}public synchronized void createTable() {Table table = new Table();tables.put(table.getId(), table);}public synchronized void destroyTable(Table table) {tables.remove(table.getId());} }

由于我們需要保護單個表的完整性,因此join()和leave()方法中的同步仍然像我們之前的示例中那樣。 因此, ConcurrentHashMap在這方面沒有幫助。 但是,由于我們還在createTable()和destroyTable()方法中創(chuàng)建新表并銷毀表,因此對ConcurrentHashMap的所有這些操作都是完全并發(fā)的,從而允許增加或減少并行表的數(shù)量。

其他提示和技巧

  • 降低鎖的可見性。 在上面的示例中,這些鎖被聲明為公共鎖,因此對于世界都是可見的,因此有可能其他人也會通過鎖定您精心挑選的監(jiān)視器來破壞您的工作。
  • 請查看java.util.concurrent.locks,以查看在那里實施的任何鎖定策略是否都會改善解決方案。
  • 使用原子操作。 我們在上面的示例中實際進行的簡單計數(shù)器增加實際上并不需要鎖定。 用AtomicInteger替換計數(shù)跟蹤中的Integer最適合此示例。

希望本文能幫助您解決鎖爭用問題,而無論您使用的是Plumbr 自動鎖檢測解決方案還是從線程轉(zhuǎn)儲中手動提取信息。

Plumbr是唯一可以通過解釋應(yīng)用程序性能數(shù)據(jù)來自動檢測Java性能問題根本原因的解決方案。

翻譯自: https://www.javacodegeeks.com/2015/01/improving-lock-performance-in-java.html

java鎖性能對比

總結(jié)

以上是生活随笔為你收集整理的java锁性能对比_提高Java的锁性能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。