并發優化–減少鎖粒度

在高負載多線程應用程序中,性能非常重要。 開發人員必須意識到并發問題才能獲得更好的性能。 當我們需要并發時,我們通常擁有必須由兩個或更多線程共享的資源。

在這種情況下,我們有一個競爭條件 ,其中只有一個線程(在資源上)將獲得鎖,而所有其他需要該鎖的線程將被阻塞。 此同步功能不是免費提供的。 JVM和OS都會消耗資源,以便為您提供有效的并發模型。 使并發實現資源密集的三個最基本的因素是:

  • 上下文切換
  • 內存同步
  • 封鎖

    為了編寫優化的代碼進行同步,您必須了解這三個因素以及如何減少它們。 編寫此類代碼時,必須注意許多事項。 在本文中,我將向您展示一種通過減少鎖的粒度來減少這些因素的技術。

    從基本規則開始: 不要將鎖持有超過必要的時間。

    獲取鎖之前 ,請做任何您需要做的事情, 僅將鎖用于對同步資源進行操作并立即釋放它。 看一個簡單的例子:

    public class HelloSync {private Map dictionary = new HashMap();public synchronized void borringDeveloper(String key, String value) {long startTime = (new java.util.Date()).getTime();value = value + "_"+startTime;dictionary.put(key, value);System.out.println("I did this in "+((new java.util.Date()).getTime() - startTime)+" miliseconds");}
    }

    在此示例中,我們違反了基本規則,因為我們創建了兩個Date對象,調用System.out.println()并執行許多String串聯。 唯一需要同步的動作是動作:“ dictionary.put(key,value); ”更改代碼并將同步從方法范圍移到這一行。 更好的代碼是這樣的:

    public class HelloSync {private Map dictionary = new HashMap();public void borringDeveloper(String key, String value) {long startTime = (new java.util.Date()).getTime();value = value + "_"+startTime;synchronized (dictionary) {dictionary.put(key, value);}System.out.println("I did this in "+((new java.util.Date()).getTime() - startTime)+" miliseconds");}
    }

    上面的代碼可以寫得更好,但是我只想給你個想法。 如果想知道如何做,請檢查java.util.concurrent.ConcurrentHashMap 。

    那么,如何減少鎖的粒度呢? 簡而言之,通過盡可能少地請求鎖。 基本思想是使用單獨的鎖來保護一個類的多個獨立狀態變量,而不是在類范圍內僅具有一個鎖。 看看我在許多應用程序中看到的這個簡單示例。

    public class Grocery {private final ArrayList fruits = new ArrayList();private final ArrayList vegetables = new ArrayList();public synchronized void addFruit(int index, String fruit) {fruits.add(index, fruit);}public synchronized void removeFruit(int index) {fruits.remove(index);}public synchronized void addVegetable(int index, String vegetable) {vegetables.add(index, vegetable);}public synchronized void removeVegetable(int index) {vegetables.remove(index);}
    }

    雜貨店老板可以在他的雜貨店添加水果和蔬菜/從中刪除水果和蔬菜。 雜貨店的這種實現使用基本的雜貨店鎖來保護水果和蔬菜,因為同步是在方法范圍內完成的。 除了使用這種胖鎖,我們可以使用兩個單獨的守護程序,每種資源(水果和蔬菜)使用一個。 檢查下面的改進代碼。

    public class Grocery {private final ArrayList fruits = new ArrayList();private final ArrayList vegetables = new ArrayList();public void addFruit(int index, String fruit) {synchronized(fruits) fruits.add(index, fruit);}public void removeFruit(int index) {synchronized(fruits) {fruits.remove(index);}}public void addVegetable(int index, String vegetable) {synchronized(vegetables) vegetables.add(index, vegetable);}public void removeVegetable(int index) {synchronized(vegetables) vegetables.remove(index);}
    }

    使用兩個防護裝置(拆分鎖)后,我們看到的鎖定流量將少于原始的胖鎖。 當我們將其應用于具有中等鎖爭用的鎖時,此技術會更好地工作。 如果我們將其應用于具有輕微爭用的鎖,則收益很小,但仍為正值。 如果我們將其應用于爭用較大的鎖,則結果并不總是更好,您必須意識到這一點。

    請出于良心使用此技術。 如果您懷疑這是一個爭用鎖,請按照以下步驟操作:

    • 確認您的生產需求量,將其乘以3或5(即使您愿意準備,甚至乘以10)。
    • 根據新流量在您的測試平臺上運行適當的測試。
    • 比較兩個解決方案,然后才選擇最合適的解決方案。

      有更多技術可以提高同步性能,但是對于所有技術,基本規則是: 保持鎖的時間不要超過必要的時間

      正如我已經向您解釋的那樣,此基本規則可以翻譯為“盡可能少地尋求鎖”,也可以翻譯為其他翻譯(解決方案),我將在以后的文章中嘗試描述它們。

      另外兩個重要的建議:

      • 請注意java.util.concurrent包(和子包) 中的類,因為它們有非常聰明和有用的實現。
      • 通過使用良好的設計模式,大多數時候并發代碼可以最小化。 始終牢記企業集成模式 ,它們可以節省您的時間。

        參考: 減少鎖粒度–我們Java的 JCG合作伙伴 Adrianos Dadis的并發優化 ,Integration and the sources 的優點 。

        相關文章 :
        • Java并發教程–信號量
        • Java并發教程–重入鎖
        • Java并發教程–線程池
        • Java并發教程–可調用,將來
        • Java并發教程–阻塞隊列
        • Java并發教程– CountDownLatch
        • Java Fork / Join進行并行編程
        • Java內存模型–快速概述和注意事項
        • Java教程和Android教程列表

        翻譯自: https://www.javacodegeeks.com/2011/10/concurrency-optimization-reduce-lock.html

        本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
        如若轉載,請注明出處:http://www.pswp.cn/news/374202.shtml
        繁體地址,請注明出處:http://hk.pswp.cn/news/374202.shtml
        英文地址,請注明出處:http://en.pswp.cn/news/374202.shtml

        如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

        相關文章

        Java1.5增加了新特性:可變參數

        /*Java 可變參數Java1.5增加了新特性:可變參數:適用于參數個數不確定,類型確定的情況,java把可變參數當做數組處理。注意:可變參數必須位于最后一項。當可變參數個數多余一個時,必將有一個不是最后一項&…

        C語言代碼規范(十)花里胡哨代碼鑒賞

        一、宏定義篇 1、作者的目的是防止GPIO口賦值超過1。但是有明顯自覺高人一等,瞧不起讀者的感覺。 uint8_t not_func(uint8_t sw) {return (sw?1:0); }#define LED1(sw) PA12not_func(sw)修改建議: #define LED1 PA12 #define LED_ON 0 #de…

        python-break循環中斷

        Python break語句,就像在C語言中,打破了最小封閉for或while循環。 break語句用來終止循環語句,即循環條件沒有False條件或者序列還沒被完全遞歸完,也會停止執行循環語句。 break語句用在while和for循環中。 如果您使用嵌套循環&am…

        正則表達式驗證六位數以上數字,符號,字母任意兩種混合的密碼驗證策略

        ^(?![0-9]$)(?![a-zA-Z]$)(?!([^(0-9a-zA-Z)]|[\(\)])$)([^(0-9a-zA-Z)]|[\(\)]|[a-zA-Z]|[0-9]){6,}$這個正則如果是單獨的數字,字符和符號,是不能通過的,少于6位也不行,希望大家可以繼續驗證正確性吧轉載于:https://www.cnbl…

        python post請求實例_Python使用requests發送POST請求實例代碼

        本文研究的主要是Python使用requests發送POST請求的相關內容,具體介紹如下。 一個http請求包括三個部分,為別為請求行,請求報頭,消息主體,類似以下這樣: 請求行 請求報頭 消息主體 HTTP協議規定post提交的數…

        Java Micro-Benchmarking:如何編寫正確的基準

        幾個月前,我寫了一篇文章比較循環的短索引的性能 。 我問自己關于使用短褲作為循環迭代次數很少的循環的性能。 在Java語言中,所有對整數的操作都是int進行的。 因此,如果我們使用short作為循環索引,則在每次迭代時都將進行類型轉…

        新唐M031學習筆記(一)定時器基礎計數應用

        先上代碼 void Hw_Timer0_Init(void) {//20:100ms 200:10ms 2000:1ms 20000:100us 200000:10us TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 200000);/* Update prescale to set proper resolution. */TIMER_SET_PRESCALE_VALUE(TIMER0, 1); /* Enable Timer0 interrupt */TI…

        java三元操作符注意

        /* 三元操作符的類型務必一致 */ public class proposal_3 {public static void main(String[] args) {int i80;String sString.valueOf(i<90?90:100);String s1String.valueOf(i<90?90:100.0);if(s.equals(s1))System.out.println("s和s1相等&#xff01;"…

        緩解口臭可以喝一種水

        河南中醫學院第一附屬醫院耳鼻喉科主任醫師梅祥勝點評&#xff1a;通常情況下&#xff0c;口臭跟脾胃濕熱有關。中醫講&#xff1a;“胃主受納&#xff0c;脾主運化&#xff1b;胃氣主降&#xff0c;使飲食物及 其糟粕得以下行&#xff0c;脾氣主升&#xff0c;則飲食物之精華得…

        asp.net+mvc+easyui+sqlite 簡單用戶系統學習之旅(二)—— easyui的簡單實用

        下面開始在UserManager.Web中利用easyUI構建web。 1. 先刪除自帶的controllers、models和views&#xff08;里面的shared和web.config可以保存&#xff09;下面的文件 2. 要利用easyUI&#xff0c;首先去網上下載jquery-easyui-1.3.2.zip&#xff0c;同時下載一份EasyUI-1.3.2.…

        adc如何獲取周期_LOL:千玨擁有ADC最需要的位移和無敵能力,為什么沒人用她打下路?...

        — 點擊藍字 關注我們 —英雄聯盟自國服上線以來&#xff0c;已經陪伴玩家走過了9個年頭&#xff0c;目前英雄聯盟中的英雄數量已經達到了151位&#xff0c;每一位都各具特色。千玨是一位深受玩家們喜愛的英雄&#xff0c;其在官方英雄的定位中&#xff0c;屬于打野英雄&#x…

        航順HK32F030MF4P6 RST作GPIO SWCLK作EXTI5 SWDIO作ADC_AIN0

        老習慣&#xff0c;先上代碼 void Hw_Input_Chage_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_IOMUX, ENABLE);GPIOMUX->NRST_PIN_KEY (uint32_t)(0x00005AE1); //KEY…

        centos7.2下編譯安裝git

        centos最新的7.2版本&#xff0c;git居然是1.8&#xff0c;而最新的git版本是2.9 差的太多了&#xff0c;何況git2.0后有大更新。于是&#xff0c;我決定編譯安裝。中間有一點小破折&#xff0c;記錄一下&#xff0c;備忘。 1&#xff0c;下載最新的源碼&#xff0c;網址&#…

        java務必讓常量的值在運行期保持不變

        /* 常量就是常量&#xff0c;在編譯期就必須確定其值&#xff0c;不應該在運行期更改&#xff0c;否則程序的可讀性會非常差 */public class proposal_2 {interface Const{public static final int RAND_CONSTnew Random().nextInt();}public static void main(String[] arg…

        Java并發教程–信號量

        這是我們將要進行的Java并發系列的第一部分。 具體來說&#xff0c;我們將深入探討Java 1.5及更高版本中內置的并發工具。 我們假設您對同步和易失性關鍵字有基本的了解。 第一篇文章將介紹信號量-特別是對信號量進行計數 。 信號量是用于限制對資源訪問的經常被誤解和使用不足…

        android surfaceview 大小_Android 使用Camera2 API采集視頻數據

        Android 視頻數據采集系列的最后一篇出爐了&#xff0c;和前兩篇文章想比&#xff0c;這篇文章從系統API層面進行一些探索&#xff0c;涉及到的細節更多。初次接觸 Camera2 API 會覺得它的使用有些繁瑣&#xff0c;涉及到的類有些多&#xff0c;不過就像第一次使用Activity, Fr…

        java生成隨機字符串

        學習java comparable特性時候&#xff0c;定義如下Student類&#xff0c;需要需要隨機添加學生姓名以及學號和成績&#xff0c;這是java如何隨機生成名字&#xff0c;根據我的查詢&#xff0c;我找到目前java庫支持兩種方法。 1. org.apache.commons.lang3.RandomStringUtils類…

        使用SharedPreferenes存取數據

        //使用SharedPreference存儲數據 public void on(View view){     //獲取用戶名和密碼     String nameeditText1.getText().toString();     String numbereditText2.getText().toString();     //判斷checkBox是否為勾選      CheckBox box(CheckBox…

        使用Java VisualVM分析您的應用程序

        當您需要發現應用程序的哪個部分消耗更多的CPU或內存時&#xff0c;必須使用探查器執行此操作。 默認情況下&#xff0c;Sun JDK中附帶的一個探查器是Java VisualVM。 這個事件探查器非常簡單易用&#xff0c;功能強大。 在這篇文章中&#xff0c;我們將看到如何安裝它并使用它…

        ArcSDE for SQL Server安裝及在ArcMap中創建ArcSDE連接

        ArcSDE for SQL Server安裝及在ArcMap中創建ArcSDE連接 原文:ArcSDE for SQL Server安裝及在ArcMap中創建ArcSDE連接安裝ArcSDE for SQL Server&#xff0c;最后一步成功后的界面如下&#xff1a;在ArcMap中創建ArcSDE連接&#xff0c;截圖如下&#xff1a;posted on 2016-08-0…