一杯咖啡的時(shí)間衡怀,帶你徹底理解Java并發(fā)編程的核心概念

一杯咖啡的時(shí)間椒功,帶你徹底理解Java并發(fā)編程的核心概念

引言

作為Java程序員,你一定聽說(shuō)過"可見性"、"原子性"、"有序性"這些概念。但這些抽象的概念往往讓人難以理解粘我。今天,讓我們通過一個(gè)簡(jiǎn)單的辦公室場(chǎng)景痹换,來(lái)重新認(rèn)識(shí)這些概念征字。

一、Java內(nèi)存模型:一個(gè)現(xiàn)代化辦公室

想象一下娇豫,我們的辦公室就是一個(gè)小型的公司:

  • 公告板(主內(nèi)存):放在大廳中央
  • 員工的記事本(工作內(nèi)存):每個(gè)人自己隨身攜帶
  • 各位員工(線程):來(lái)來(lái)往往處理各種事務(wù)

1.1 工作內(nèi)存 vs 線程棧:不同的抽象層面

在討論并發(fā)問題之前柔纵,我們先來(lái)理清兩個(gè)容易混淆的概念:

public class Employee {
    private static int companyMoney = 100000;  // 公司賬戶余額-主內(nèi)存
    
    public void processPayment() {
        int salary = 5000;            // 局部變量-線程棧
        companyMoney -= salary;       // 共享變量-涉及工作內(nèi)存
    }
}

線程棧

  • 就像員工的個(gè)人辦公桌
  • 存放:個(gè)人的文件和工具(局部變量)
  • 特點(diǎn):只有自己能用,不需要和別人共享

工作內(nèi)存

  • 就像員工的記事本
  • 存放:公共信息的備份(共享變量的副本)
  • 特點(diǎn):需要和公告板保持同步

1.2 Java內(nèi)存模型的交互規(guī)則

就像公司的規(guī)章制度一樣锤躁,Java內(nèi)存模型定義了幾個(gè)重要的規(guī)則:

  1. 主內(nèi)存與工作內(nèi)存的交互
class CompanyProcess {
    // 主內(nèi)存變量
    volatile int documentVersion = 1;
    
    // 交互過程
    void updateDocument() {
        // 1. 從主內(nèi)存讀取到工作內(nèi)存
        // 2. 在工作內(nèi)存中修改
        // 3. 寫回主內(nèi)存
        documentVersion++;
    }
}
  1. 變量的原子操作
  • read:從公告板讀取信息
  • load:抄寫到記事本
  • use:查看記事本信息
  • assign:在記事本修改
  • store:準(zhǔn)備更新到公告板
  • write:實(shí)際更新公告板

二搁料、并發(fā)編程的三大困擾

2.1 可見性:錯(cuò)過的會(huì)議通知

問題場(chǎng)景

public class MeetingNotice {
    private boolean meetingScheduled = false;
    
    // 行政小張:發(fā)布會(huì)議通知
    public void scheduleMeeting() {
        prepareMeeting();
        meetingScheduled = true;
    }
    
    // 小李:一直在等通知
    public void waitForMeeting() {
        while (!meetingScheduled) {
            // 不斷查看記事本
        }
        attendMeeting();
    }
}

解決方案

public class MeetingNotice {
    // 重要通知必須直接看公告板
    private volatile boolean meetingScheduled = false;
    // 其他代碼不變
}

2.2 原子性:混亂的會(huì)議室預(yù)訂

問題場(chǎng)景

public class MeetingRoom {
    private boolean isBooked = false;
    
    public void book() {
        // 以下三步不是原子操作
        if (!isBooked) {           // 1. 檢查狀態(tài)
            validateEmployee();     // 2. 驗(yàn)證員工身份
            isBooked = true;       // 3. 更新狀態(tài)
        }
    }
}

解決方案

public class MeetingRoom {
    private boolean isBooked = false;
    
    // 加鎖保證原子性
    public synchronized void book() {
        if (!isBooked) {
            validateEmployee();
            isBooked = true;
        }
    }
}

2.3 有序性:混亂的入職流程

問題場(chǎng)景

public class Onboarding {
    private boolean workstationReady;
    private boolean accountCreated;
    
    public void prepare() {
        workstationReady = true;    // 可能和下面的順序互換
        accountCreated = true;
    }
    
    public void checkStatus() {
        if (accountCreated && !workstationReady) {
            // 賬號(hào)創(chuàng)建了但工位沒準(zhǔn)備好?
        }
    }
}

解決方案

public class Onboarding {
    private volatile boolean workstationReady;
    private volatile boolean accountCreated;
    
    public synchronized void prepare() {
        workstationReady = true;
        accountCreated = true;
    }
}

三系羞、深入理解happens-before

就像公司的工作流程一樣郭计,happens-before規(guī)則確定了操作的先后順序:

  1. 程序順序規(guī)則:
// 代碼中的先后順序
void process() {
    step1();  // 一定在step2之前
    step2();
}
  1. volatile變量規(guī)則:
volatile boolean flag;
int data;

// 線程A
data = 42;
flag = true;

// 線程B
if (flag) {
    // 一定能看到data = 42
}
  1. 傳遞性規(guī)則:
// A happens-before B
// B happens-before C
// 則A happens-before C

四、實(shí)踐建議

  1. 優(yōu)先使用高層同步工具
// 不要這樣
private volatile boolean flag;
private volatile int count;

// 建議這樣
private AtomicBoolean flag = new AtomicBoolean();
private AtomicInteger count = new AtomicInteger();
  1. 正確使用synchronized
// 同步代碼塊要夠小椒振,但也要確保完整性
synchronized void transfer(Account from, Account to) {
    // 放在一個(gè)同步塊中
    from.debit(amount);
    to.credit(amount);
}
  1. volatile的適用場(chǎng)景
public class Config {
    private volatile String config;
    // 適用于單個(gè)變量的讀寫
    // 不適用于復(fù)合操作
}

總結(jié)

通過辦公室的日常場(chǎng)景昭伸,我們可以更直觀地理解Java并發(fā)編程中的核心概念:

  • 可見性:就像必須及時(shí)查看公告板
  • 原子性:就像會(huì)議室預(yù)訂必須一氣呵成
  • 有序性:就像入職流程必須按步驟來(lái)

記住,編寫并發(fā)程序時(shí):

  1. 優(yōu)先使用成熟的并發(fā)工具類
  2. 理解清楚共享變量的訪問規(guī)則
  3. 正確使用synchronized和volatile關(guān)鍵字

這些原則不僅適用于Java澎迎,在其他編程語(yǔ)言中也同樣重要庐杨。希望這篇文章能幫助你更好地理解并發(fā)編程的核心概念!

參考資料

  1. 《Java并發(fā)編程實(shí)戰(zhàn)》
  2. 《深入理解Java虛擬機(jī)》
  3. JSR-133: Java Memory Model and Thread Specification
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末夹供,一起剝皮案震驚了整個(gè)濱河市灵份,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哮洽,老刑警劉巖填渠,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鸟辅,居然都是意外死亡氛什,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門匪凉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)枪眉,“玉大人,你說(shuō)我怎么就攤上這事再层∶惩” “怎么了堡纬?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)萨脑。 經(jīng)常有香客問我隐轩,道長(zhǎng)饺饭,這世上最難降的妖魔是什么渤早? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮瘫俊,結(jié)果婚禮上鹊杖,老公的妹妹穿的比我還像新娘。我一直安慰自己扛芽,他們只是感情好骂蓖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著川尖,像睡著了一般登下。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叮喳,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天被芳,我揣著相機(jī)與錄音,去河邊找鬼馍悟。 笑死畔濒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锣咒。 我是一名探鬼主播侵状,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼毅整!你這毒婦竟也來(lái)了趣兄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤悼嫉,失蹤者是張志新(化名)和其女友劉穎诽俯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體承粤,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡暴区,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辛臊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仙粱。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖彻舰,靈堂內(nèi)的尸體忽然破棺而出伐割,到底是詐尸還是另有隱情候味,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布隔心,位于F島的核電站白群,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏硬霍。R本人自食惡果不足惜帜慢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望唯卖。 院中可真熱鬧粱玲,春花似錦、人聲如沸拜轨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)橄碾。三九已至卵沉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間法牲,已是汗流浹背史汗。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皆串,地道東北人淹办。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像恶复,于是被迫代替她去往敵國(guó)和親怜森。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容