什 么 是 Java 的 內(nèi) 存 模 型 , Java 中 各 個(gè) 線 程 是 怎 么 彼 此 看 到 對(duì) 方 的 變 量 的 ?
java 的 內(nèi) 存 模 型 定 義 了 程 序 中 各 個(gè) 變 量 的 訪 問(wèn) 規(guī) 則 假哎, 即 在 虛 擬 機(jī) 中 將 變 量 存 儲(chǔ) 到 內(nèi) 存 和 從 內(nèi) 存 中 取 出 這 樣 的 底 層 細(xì) 節(jié) 。
此 處 的 變 量 包 括 實(shí) 例 字 段 作彤、 靜 態(tài) 字 段 和 構(gòu) 成 數(shù) 組 對(duì) 象 的 元 素 玛歌, 但 是 不 包 括 局 部 變 量 和 方 法 參 數(shù) , 因 為 這 些 是 線 程 私 有 的 崖技, 不 會(huì) 被 共 享 逻住, 所 以 不 存 在 競(jìng) 爭(zhēng) 問(wèn) 題 钟哥。
Java 中 各 個(gè) 線 程 是 怎 么 彼 此 看 到 對(duì) 方 的 變 量 的 呢 ? Java 中 定 義 了 主 內(nèi) 存 與 工 作 內(nèi) 存 的 概 念 :
所 有 的 變 量 都 存 儲(chǔ) 在 主 內(nèi) 存 鄙信, 每 條 線 程 還 有 自 己 的 工 作 內(nèi) 存 瞪醋, 保 存 了 被 該 線 程 使 用 到 的 變 量 的 主 內(nèi) 存 副 本 拷 貝 。
線 程 對(duì) 變 量 的 所 有 操 作 ( 讀 取 装诡、 賦 值 ) 都 必 須 在 工 作 內(nèi) 存 中 進(jìn) 行 银受, 不 能 直 接 讀 寫(xiě) 主 內(nèi) 存 的 變 量 。 不 同 的 線 程 之 間 也 無(wú) 法 直 接 訪 問(wèn) 對(duì) 方 工 作 內(nèi) 存 的 變 量 鸦采, 線 程 間 變 量 值 的 傳 遞 需 要 通 過(guò) 主 內(nèi) 存 宾巍。
請(qǐng) 談 談 volatile 有 什 么 特 點(diǎn) , 為 什 么 它 能 保 證 變 量 對(duì) 所 有 線 程 的 可 見(jiàn) 性 渔伯?
關(guān) 鍵 字 volatile 是 Java 虛 擬 機(jī) 提 供 的 最 輕 量 級(jí) 的 同 步 機(jī) 制 顶霞。 當(dāng) 一 個(gè) 變 量 被 定 義 成 volatile 之 后 , 具 備 兩 種 特 性 :
- 保 證 此 變 量 對(duì) 所 有 線 程 的 可 見(jiàn) 性 锣吼。 當(dāng) 一 條 線 程 修 改 了 這 個(gè) 變 量 的 值 选浑, 新 值 對(duì) 于 其 他 線 程 是 可 以 立 即 得 知 的 。 而 普 通 變 量 做 不 到 這 一 點(diǎn) 玄叠。
- 禁 止 指 令 重 排 序 優(yōu) 化 古徒。 普 通 變 量 僅 僅 能 保 證 在 該 方 法 執(zhí) 行 過(guò) 程 中 , 得 到正 確 結(jié) 果 读恃, 但 是 不 保 證 程 序 代 碼 的 執(zhí) 行 順 序 隧膘。
既 然 volatile 能 夠 保 證 線 程 間 的 變 量 可 見(jiàn) 性 , 是 不 是 就 意 味 著 基 于 volatile 變 量 的 運(yùn) 算 就 是 并 發(fā) 安 全 的 寺惫?
顯 然 不 是 的 疹吃。 基 于 volatile 變 量 的 運(yùn) 算 在 并 發(fā) 下 不 一 定 是 安 全 的 。
volatile 變 量 在 各 個(gè) 線 程 的 工 作 內(nèi) 存 西雀, 不 存 在 一 致 性 問(wèn) 題 ( 各 個(gè) 線 程 的 工 作 內(nèi) 存 中 volatile 變 量 萨驶, 每 次 使 用 前 都 要 刷 新 到 主 內(nèi) 存 ) 。
但 是 Java 里 面 的 運(yùn) 算 并 非 原 子 操 作 蒋搜, 導(dǎo) 致 volatile 變 量 的 運(yùn) 算 在 并 發(fā) 下 一 樣 是 不 安 全 的 篡撵。
請(qǐng) 對(duì) 比 下 volatile 對(duì) 比 Synchronized 的 異 同
Synchronized 既 能 保 證 可 見(jiàn) 性 , 又 能 保 證 原 子 性 豆挽, 而 volatile 只 能 保 證 可 見(jiàn) 性 育谬, 無(wú) 法 保 證 原 子 性 。
Thread Local 和 Synchonized 都 用 于 解 決 多 線 程 并 發(fā) 訪 問(wèn) 帮哈, 防 止 任 務(wù) 在 共 享 資 源 上 產(chǎn) 生 沖 突 膛檀。 但 是 Thread Local 與 Synchronized 有 本 質(zhì) 的 區(qū) 別 。
Synchronized 用 于 實(shí) 現(xiàn) 同 步 機(jī) 制 , 是 利 用 鎖 的 機(jī) 制 使 變 量 或 代 碼 塊 在 某 一 時(shí) 該 只 能 被 一 個(gè) 線 程 訪 問(wèn) 咖刃, 是 一 種 “ 以 時(shí) 間 換 空 間 ” 的 方 式 泳炉。 而 Thread Local 為 每 一 個(gè) 線 程 都 提 供 了 變 量 的 副 本 , 使 得 每 個(gè) 線 程 在 某 一 時(shí) 間 訪 問(wèn) 到 的 并 不 是 同 一 個(gè) 對(duì) 象 嚎杨, 根 除 了 對(duì) 變 量 的 共 享 花鹅, 是 一 種
“ 以 空 間 換 時(shí) 間 ” 的 方 式 。
請(qǐng) 談 談 Thread Local 是 怎 么 解 決 并 發(fā) 安 全 的
Thread Local 這 是 Java 提 供 的 一 種 保 存 線 程 私 有 信 息 的 機(jī) 制 枫浙, 因 為 其 在 整 個(gè) 線 程 生 命 周 期 內(nèi) 有 效 刨肃, 所 以 可 以 方 便 地 在 一 個(gè) 線 程 關(guān) 聯(lián) 的 不 同 業(yè) 務(wù) 模 塊 之 間 傳 遞 信 息 , 比 如 事 務(wù) ID箩帚、 Cookie 等 上 下 文 相 關(guān) 信 息 真友。
Thread Local 為 每 一 個(gè) 線 程 維 護(hù) 變 量 的 副 本 , 把 共 享 數(shù) 據(jù) 的 可 見(jiàn) 范 圍 限 制 在 同 一 個(gè) 線 程 之 內(nèi) 紧帕, 其 實(shí) 現(xiàn) 原 理 是 盔然, 在 Thread Local 類(lèi) 中 有 一 個(gè) Map, 用 于 存 儲(chǔ) 每 一 個(gè) 線 程 的 變 量 的 副 本 是嗜。
很 多 人 都 說(shuō) 要 慎 用 Thread Local愈案, 談 談 你 的 理 解 , 使 用 Thread Local 需 要 注 意 些 什 么 鹅搪?
Thread Local 的 實(shí) 現(xiàn) 是 基 于 一 個(gè) 所 謂 的 Thread Local Map刻帚, 在 Thread Local Map 中 , 它 的 key 是 一 個(gè) 弱 引 用 涩嚣。
通 常 弱 引 用 都 會(huì) 和 引 用 隊(duì) 列 配 合 清 理 機(jī) 制 使 用 , 但 是 Thread Local 是 個(gè) 例 外 掂僵, 它 并 沒(méi) 有 這 么 做 航厚。
這 意 味 著 , 廢 棄 項(xiàng) 目 的 回 收 依 賴 于 顯 式 地 觸 發(fā) 锰蓬, 否 則 就 要 等 待 線 程 結(jié)束 幔睬, 進(jìn) 而 回 收 相 應(yīng) Thread Local Map! 這 就 是 很 多 OOM 的 來(lái) 源 芹扭, 所 以 通 常 都 會(huì) 建 議 麻顶, 應(yīng) 用 一 定 要 自 己 負(fù) 責(zé) remove, 并 且 不 要 和 線 程 池 配 合 舱卡, 因 為 worker 線 程 往 往 是 不 會(huì) 退 出 的 辅肾。