網易Java研發麵試官眼中的Java併發——安全性、活躍性、性能

来源:https://www.cnblogs.com/Java-no-1/archive/2019/07/05/11141000.html
-Advertisement-
Play Games

一. 安全性問題 線程安全的本質是正確性,而正確性的含義是程式按照預期執行 理論上線程安全的程式,應該要避免出現可見性問題(CPU緩存)、原子性問題(線程切換)和有序性問題(編譯優化) 需要分析是否存線上程安全問題的場景:存在共用數據且數據會發生變化,即有多個線程會同時讀寫同一個數據 針對該理論的解 ...


一. 安全性問題

  1. 線程安全的本質是正確性,而正確性的含義是程式按照預期執行

  2. 理論上線程安全的程式,應該要避免出現可見性問題(CPU緩存)、原子性問題(線程切換)和有序性問題(編譯優化)

  3. 需要分析是否存線上程安全問題的場景:存在共用數據且數據會發生變化,即有多個線程會同時讀寫同一個數據

  4. 針對該理論的解決方案:不共用數據,採用線程本地存儲(Thread Local Storage,TLS);不變模式

Ⅰ. 數據競爭

數據競爭(Data Race):多個線程同時訪問同一數據,並且至少有一個線程會寫這個數據

1. add

private static final int MAX_COUNT = 1_000_000;
private long count = 0;
// 非線程安全
public void add() {
    int index = 0;
    while (++index < MAX_COUNT) {
        count += 1;
    }
}

 

2. add + synchronized

private static final int MAX_COUNT = 1_000_000;
private long count = 0;
public synchronized long getCount() {
    return count;
}
public synchronized void setCount(long count) {
    this.count = count;
}
// 非線程安全
public void add() {
    int index = 0;
    while (++index < MAX_COUNT) {
        setCount(getCount() + 1);
    }
}
  • 假設count=0,當兩個線程同時執行getCount(),都會返回0
  • 兩個線程執行getCount()+1,結果都是1,最終寫入記憶體是1,不符合預期,這種情況為竟態條件

Ⅱ. 竟態條件

  1. 竟態條件(Race Condition):程式的執行結果依賴於線程執行的順序
  2. 在併發環境里,線程的執行順序是不確定的
    • 如果程式存在竟態條件問題,那麼意味著程式的執行結果是不確定的

1. 轉賬

public class Account {
    private int balance;
    // 非線程安全,存在竟態條件,可能會超額轉出
    public void transfer(Account target, int amt) {
        if (balance > amt) {
            balance -= amt;
            target.balance += amt;
        }
    }
}

 

Ⅲ. 解決方案

面對數據競爭和竟態條件問題,可以通過互斥的方案來實現線程安全,互斥的方案可以統一歸為鎖

二. 活躍性問題

活躍性問題:某個操作無法執行下去,包括三種情況:死鎖、活鎖、饑餓

Ⅰ. 死鎖

  1. 發生死鎖後線程會相互等待,表現為線程永久阻塞
  2. 解決死鎖問題的方法是規避死鎖(破壞發生死鎖的條件之一)
    • 互斥:不可破壞,鎖定目的就是為了互斥
    • 占有且等待:一次性申請所有需要的資源
    • 不可搶占:當線程持有資源A,並嘗試持有資源B時失敗,線程主動釋放資源A
    • 迴圈等待:將資源編號排序,線程申請資源時按遞增(或遞減)的順序申請

Ⅱ. 活鎖

  • 活鎖:線程並沒有發生阻塞,但由於相互謙讓,而導致執行不下去
  • 解決方案:在謙讓時,嘗試等待一個隨機時間(分散式一致演算法Raft也有採用)

Ⅲ. 饑餓

  1. 饑餓:線程因無法訪問所需資源而無法執行下去
    • 線程的優先順序是不相同的,在CPU繁忙的情況下,優先順序低的線程得到執行的機會很少,可能發生線程饑餓
    • 持有鎖的線程,如果執行的時間過長(持有的資源不釋放),也有可能導致饑餓問題
  2. 解決方案
    • 保證資源充足
    • 公平地分配資源(公平鎖) – 比較可行
    • 避免持有鎖的線程長時間執行

三. 性能問題

  1. 鎖的過度使用可能會導致串列化的範圍過大,這會影響多線程優勢的發揮(併發程式的目的就是為了提升性能)
  2. 儘量減少串列,假設串列百分比為5%,那麼多核多線程相對於單核單線程的提升公式(Amdahl定律)
    S=1/((1-p)+p/n),n為CPU核數,p為並行百分比,(1-p)為串列百分比
  • 假如p=95%,n無窮大,加速比S的極限為20,即無論採用什麼技術,最高只能提高20倍的性能

Ⅰ. 解決方案

  1. 無鎖演算法和數據結構
    • 線程本地存儲(Thread Local Storage,TLS)
    • 寫入時複製(Copy-on-write)
    • 樂觀鎖
    • JUC中的原子類
    • Disruptor(無鎖的記憶體隊列)
  2. 減少鎖持有的時間,互斥鎖的本質是將並行的程式串列化,要增加並行度,一定要減少持有鎖的時間
    • 使用細粒度鎖,例如JUC中的ConcurrentHashMap(分段鎖)
    • 使用讀寫鎖,即讀是無鎖的,只有寫才會互斥的

Ⅱ. 性能指標

  1. 吞吐量:在單位時間內能處理的請求數量,吞吐量越高,說明性能越好
  2. 延遲:從發出請求到收到響應的時間,延遲越小,說明性能越好
  3. 併發量:能同時處理的請求數量,一般來說隨著併發量的增加,延遲也會增加,所以延遲一般是基於併發量來說的

寫在最後

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • java 手寫 jvm高性能緩存,鍵值對存儲,隊列存儲,存儲超時設置 緩存介面 package com.ws.commons.cache; public interface ICache { void expire(String key, int timeOutSecond); void leftP ...
  • 基本輸出 python中的輸出使用關鍵字--print,與python2不同的是,python3的輸出後面必須要加括弧,示例如下: python3.0以上輸出: python2.0以上的輸出: 格式化的輸出 在程式中看到輸出的語句存在%(占位符),那麼這就是表示格式化的輸出 換行輸出 如果在輸出的語 ...
  • 檢查文件是否存在 在此程式同目錄下創建log.txt文件,以檢測。 檢查文件是否不存在 讀取文件內容 在此程式同目錄下創建name.txt文件,以檢測。 寫入文件 在此程式同目錄下創建hello_world文件。 創建臨時文件 計算文件行數 在程式同目錄下創建"names.txt"文件,隨便寫幾行字 ...
  • 自定義錯誤類型 Go中可以使用 創建錯誤信息,也可以通過創建自定義錯誤類型來滿足需求。 是一個介面類型,所有實現該介面的類型都可以當作一個錯誤類型。 記錄日誌 捕獲異常 ...
  • Win10下安裝Hadoop3.1.2詳解 嘗試在本地win10上安裝hadoop,在官網選擇了最新的hadoop版本,就是這裡開始給自己挖了坑,對著網上的博客一頓操作,發現節點一直啟動不成功。本著不放棄的原則,在不停的配置過程中繼續折騰,終於解決問題。 安裝環境 JDK 1.8 Windows10 ...
  • 一、JDK 1.含義:Java開發工具包。 2.做Java開發之前必須安裝的一個工具包,​下載地址:https://www.oracle.com/index.html 3.Java包括三大塊內容: (1)JavaSE(Java標準版),這是基礎必知必會 (2)JavaEE(Java企業版) (3)J ...
  • 1.Redis單進程: 單進程模型來處理客戶端的請求。對讀寫等事件的響應是通過對epoll函數的包裝來做到的。Redis的實際處理速度完全依靠主進程的執行效率。epoll是Linux內核為處理大批量文件描述符而作了改進的epoll,是Linux下多路復用IO介面select/poll的增強版本,它能 ...
  • [TOC] 1.while迴圈 死迴圈 打斷死迴圈: 關鍵字: 2.字元串格式化: 3.運算符 4.編碼 四種(重要) 單位轉換 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...