Heng Lin

  • 主頁
  • 所有文章
搜尋文章 關於我

Heng Lin

  • 主頁
  • 所有文章

Java volatile 的使用時機

2020-01-03

最近重頭複習 java multi-thread 的相關知識,紀錄下來方便自己往後開發時可參照
今天來談 volatile 它可以當成一個輕量的鎖
我通常使用它來控制 multi-thread 共享變數,用來通知多個 thread 任務完成後正常離開
但它不能用於 java 計數,如 count++, index-- 之類的操作,這些動作看起來是一步,但實際上卻是三步

  1. iload_1
  2. iinc 1, 1
  3. istore_1
    若在執行期間 1 ~ 3 不能一氣呵成的執行完畢,中間被其他 thread 打斷後操作同個變數,其結果可能會與預期中的不同
    因為它不保證 atomic ,若有計數的需求需使用 AtomicInteger, AtomicReference, AtomicStampedReference 之類的 lib 來實現

在使用 volatile 之前要先了解 java thread 使用記憶體的情況
在 process 有宣告變數時主記憶體會提供空間存放變數資料 (這裡的 process 不是指 main() 因為 main() 一樣是 thread ,由 JVM 運行時創建)
但是在多個 thread 使用宣告的共享變數時,記憶體一樣會有一份共享變數資料
不同的是多個 thread 並不是直接共用此份共享變數資料
而是各自從共享變數 copy 一份變數資料到各自的 thread 中 ( cache )
當 thread 更新變數資料時,首先是改變自己內部的資料後再寫回記憶體中的那份共享變數
所以若是其他 thread 沒有從記憶體內的共享變數重新更新最資料回自己的 thread 時
會造成資料不一致的後果

那為什麼其他 thread 不更新自己變數資料呢?
這是 Java 為了性能優化而做的預設的行為
因為其他 thread 可能只有做讀取的操作,所以 Java 認為不需要再從主記憶體重新拿資料
不知道已經有 thread 已經更新變數內容

為了避免 thread 共享變數資料不一致得問題發生 volatile 就派上用場了
volatile 可以強迫 thread 更新資料回記憶體共享變數資料後並通知前他 thread 更新它們內部的資料
來保證資料的可見性
前面有說過 volatile 並不可用於計數相關的處理,因為它並不是真的鎖住整個物件
所以不保證只有一個 thread 可進入後單獨更新變數,因此當此 thread 可能在數值更新時並未 assign 回變數時
就被其他 thread 取得 cpu 控制權,並 assign 同筆資料時造成互蓋的問題

之前有做過實驗使用 10 個 thread 並將共享變數宣告為 volatile 從0一路增加到1000
在預期的情況下 10 * 1000 會是 10000 ,但在實際運行多次的情況下沒有一次得到10000
通常數值落在 7000 ~ 9000 多,就是高併發快速交錯運行下互蓋資料的後果

結論

  1. volatile 可確保資料可見性,一個 thread 更新變數,其他 thread 也會重新更新內部變數
  2. volatile 不保證 atomic,不可用於計數操作
  • java
  • thread

扫一扫,分享到微信

微信分享二维码
Java ReentrantLock 和 ReentrantReadWriteLock 的使用時機
spring cloud 使用 gradle 打包 docker image
© 2020 Heng Lin
Hexo Theme Yilia by Litten
  • 搜尋文章
  • 關於我

tag:

  • hadoop
  • big data
  • conference
  • java
  • nio
  • thread
  • unit test
  • shell
  • gradle
  • docker
  • spring cloud
  • android
  • memory leak
  • math
  • hexo
  • Blog
  • probability
  • statistics
  • clean code
  • illustrator
  • js

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • JCConf 2020

    2020-11-28

    #conference

  • Java Unit Test 使用 Mockito + Powermock (3)

    2020-08-29

    #unit test

  • Java Unit Test 使用 Mockito + Powermock (2)

    2020-06-14

    #unit test

  • Java Unit Test 使用 Mockito + Powermock (1)

    2020-04-25

    #unit test

  • 關於 Java CompletableFuture 的用法

    2020-04-19

    #java#thread

  • Java NIO ByteBuffer 基本操作圖

    2020-01-13

    #java#nio

  • 對於 Java Fork Join framework 的理解

    2020-01-07

    #java#thread

  • Java BlockingQueue 適合應用在哪些場景

    2020-01-06

    #java#thread

  • 對於 Java ThreadPoolExecutor 的理解

    2020-01-05

    #java#thread

  • Java ReentrantLock 和 ReentrantReadWriteLock 的使用時機

    2020-01-04

    #java#thread

  • Java volatile 的使用時機

    2020-01-03

    #java#thread

  • spring cloud 使用 gradle 打包 docker image

    2019-11-11

    #gradle#docker#spring cloud

  • Hadoop RecordReader

    2019-11-06

    #hadoop#big data

  • Hadoop Writable

    2019-11-03

    #hadoop#big data

  • JSDC 2019

    2019-10-26

    #conference

  • 簡易版shell script作自動化處理

    2019-10-22

    #shell

  • JCConf 2019

    2019-10-04

    #conference

  • JCConf 2018

    2018-10-21

    #conference

  • 用illustrator幫自己畫一個新頭像

    2018-07-15

    #illustrator

  • 使用視覺化來解釋數學原理的youtube - 3Blue1Brown

    2018-06-24

    #math

  • 使用 Gradle 自動初始化 Spock

    2018-05-20

    #unit test#gradle

  • 提升Socket傳送Large file的速度

    2018-05-13

    #java

  • 你真的了解Java中的Thread運作嗎? - 容易讓人誤解的synchronized method

    2018-04-29

    #java#thread

  • 從無到有DIY chart (二)

    2018-04-14

    #js

  • 從無到有DIY chart (一)

    2018-04-01

    #js

  • 標準常態分佈的機率密度函數

    2018-03-24

    #math#probability#statistics

  • Linux 如何避免重複執行特定jar

    2018-03-17

    #shell

  • 使用 WeakReference 解決 Android 發生 memory leak 問題

    2018-03-10

    #java#android#memory leak

  • 比較好的nested map寫法

    2018-03-03

    #java#clean code

  • 更換hexo themes

    2018-02-20

    #hexo

  • 第一篇Blog,從SVN到Git

    2018-02-16

    #Blog

全端工程師

60% Java
40% Javascript