網(wǎng)易Java研發(fā)面試官眼中的Java并發(fā)——安全性、活躍性、性能

一. 安全性問題

  1. 線程安全的本質(zhì)是正確性,而正確性的含義是程序按照預(yù)期執(zhí)行

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

  3. 需要分析是否存在線程安全問題的場景:存在共享數(shù)據(jù)且數(shù)據(jù)會(huì)發(fā)生變化,即有多個(gè)線程會(huì)同時(shí)讀寫同一個(gè)數(shù)據(jù)

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

Ⅰ. 數(shù)據(jù)競爭

數(shù)據(jù)競爭(Data Race):多個(gè)線程同時(shí)訪問同一數(shù)據(jù),并且至少有一個(gè)線程會(huì)寫這個(gè)數(shù)據(jù)

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);
    }
}
  • 假設(shè)count=0,當(dāng)兩個(gè)線程同時(shí)執(zhí)行g(shù)etCount(),都會(huì)返回0
  • 兩個(gè)線程執(zhí)行g(shù)etCount()+1,結(jié)果都是1,最終寫入內(nèi)存是1,不符合預(yù)期,這種情況為竟態(tài)條件

Ⅱ. 竟態(tài)條件

  1. 竟態(tài)條件(Race Condition):程序的執(zhí)行結(jié)果依賴于線程執(zhí)行的順序
  2. 在并發(fā)環(huán)境里,線程的執(zhí)行順序是不確定的
    • 如果程序存在竟態(tài)條件問題,那么意味著程序的執(zhí)行結(jié)果是不確定的

1. 轉(zhuǎn)賬

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

Ⅲ. 解決方案

面對數(shù)據(jù)競爭和竟態(tài)條件問題,可以通過互斥的方案來實(shí)現(xiàn)線程安全,互斥的方案可以統(tǒng)一歸為鎖

二. 活躍性問題

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

Ⅰ. 死鎖

  1. 發(fā)生死鎖后線程會(huì)相互等待,表現(xiàn)為線程永久阻塞
  2. 解決死鎖問題的方法是規(guī)避死鎖(破壞發(fā)生死鎖的條件之一)
    • 互斥:不可破壞,鎖定目的就是為了互斥
    • 占有且等待:一次性申請所有需要的資源
    • 不可搶占:當(dāng)線程持有資源A,并嘗試持有資源B時(shí)失敗,線程主動(dòng)釋放資源A
    • 循環(huán)等待:將資源編號排序,線程申請資源時(shí)按遞增(或遞減)的順序申請

Ⅱ. 活鎖

  • 活鎖:線程并沒有發(fā)生阻塞,但由于相互謙讓,而導(dǎo)致執(zhí)行不下去
  • 解決方案:在謙讓時(shí),嘗試等待一個(gè)隨機(jī)時(shí)間(分布式一致算法Raft也有采用)

Ⅲ. 饑餓

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

三. 性能問題

  1. 鎖的過度使用可能會(huì)導(dǎo)致串行化的范圍過大,這會(huì)影響多線程優(yōu)勢的發(fā)揮(并發(fā)程序的目的就是為了提升性能
  2. 盡量減少串行,假設(shè)串行百分比為5%,那么多核多線程相對于單核單線程的提升公式(Amdahl定律)
    S=1/((1-p)+p/n),n為CPU核數(shù),p為并行百分比,(1-p)為串行百分比
  • 假如p=95%,n無窮大,加速比S的極限為20,即無論采用什么技術(shù),最高只能提高20倍的性能

Ⅰ. 解決方案

  1. 無鎖算法和數(shù)據(jù)結(jié)構(gòu)
    • 線程本地存儲(chǔ)(Thread Local Storage,TLS)
    • 寫入時(shí)復(fù)制(Copy-on-write)
    • 樂觀鎖
    • JUC中的原子類
    • Disruptor(無鎖的內(nèi)存隊(duì)列)
  2. 減少鎖持有的時(shí)間,互斥鎖的本質(zhì)是將并行的程序串行化,要增加并行度,一定要減少持有鎖的時(shí)間
    • 使用細(xì)粒度鎖,例如JUC中的ConcurrentHashMap(分段鎖)
    • 使用讀寫鎖,即讀是無鎖的,只有寫才會(huì)互斥的

Ⅱ. 性能指標(biāo)

  1. 吞吐量:在單位時(shí)間內(nèi)能處理的請求數(shù)量,吞吐量越高,說明性能越好
  2. 延遲:從發(fā)出請求到收到響應(yīng)的時(shí)間,延遲越小,說明性能越好
  3. 并發(fā)量:能同時(shí)處理的請求數(shù)量,一般來說隨著并發(fā)量的增加,延遲也會(huì)增加,所以延遲一般是基于并發(fā)量來說的

寫在最后

  • 第一:看完點(diǎn)贊,感謝您的認(rèn)可;
  • ...
  • 第二:隨手轉(zhuǎn)發(fā),分享知識,讓更多人學(xué)習(xí)到;
  • ...
  • 第三:記得點(diǎn)關(guān)注,每天更新的?。?!
  • ...
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,899評論 0 11
  • 1. cpu通過時(shí)間片分配算法來循環(huán)執(zhí)行任務(wù),當(dāng)前任務(wù)執(zhí)行一個(gè)時(shí)間片后會(huì)切換到下一任務(wù)。但是,再切換之前會(huì)保存上一...
    冰與河豚魚閱讀 748評論 0 0
  • 一.線程安全性 線程安全是建立在對于對象狀態(tài)訪問操作進(jìn)行管理,特別是對共享的與可變的狀態(tài)的訪問 解釋下上面的話: ...
    黃大大吃不胖閱讀 963評論 0 3
  • layout: posttitle: 《Java并發(fā)編程的藝術(shù)》筆記categories: Javaexcerpt...
    xiaogmail閱讀 6,021評論 1 19
  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來是分開三篇的,后來想想還是整...
    coder_pig閱讀 1,772評論 2 17

友情鏈接更多精彩內(nèi)容