日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面试必问:读写一致性,你需要思考的问题

發布時間:2024/9/5 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试必问:读写一致性,你需要思考的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

先說明下,本文要討論的多線程讀寫是指一個線程寫,一個或多個線程讀,不包括多線程同時寫的情況。

試想下這樣一個場景:一個線程往hashmap中寫數據,一個線程往hashmap中讀數據。 這樣會有問題嗎?如果有,那是什么問題?

相信大家都知道是有問題的,但至于到底是什么問題,可能就不是那么顯而易見了。

問題有兩點。
一是內存可見性的問題,hashmap存儲數據的table并沒有用voliate修飾,也就是說讀線程可能一直讀不到數據的最新值。
二是指令重排序的問題,get的時候可能得到的是一個中間狀態的數據,我們看下put方法的部分代碼。

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { ... if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = new Node<>(hash, key, value, next); ... }

可以看到,在put操作時,如果table數組的指定位置為null,會創建一個Node對象,并放到table數組上。但我們知道jvm中?tab[i] = new Node<>(hash, key, value, next);這樣的操作不是原子的,并且可能因為指令重排序,導致另一個線程調用get取tab[i]的時候,拿到的是一個還沒有調用完構造方法的對象,導致不可預料的問題發生。

上述的兩個問題可以說都是因為HashMap中的內部屬性沒有被voliate修飾導致的,如果HashMap中的對象全部由voliate修飾,則一個線程寫,一個線程讀的情況是不會有問題(這里是我的猜測,證實這個猜測正確性的一點依據是ConcurrentHashMap的get并沒有加鎖,也就是說在Map結構里讀寫其實是不沖突)。見下方區sora-zero同學的評論

?

創建對象的原子性問題

有的同學對于?Object obj = new Object();這樣的操作在多線程的情況下會拿到一個未初始化的對象這點可能有疑惑,這里也做個簡單的說明。以上java語句分為4個步驟:

  • 在棧中分配一片空間給obj引用
  • 在jvm堆中創建一個Object對象,注意這里僅僅是分配空間,沒有調用構造方法
  • 初始化第2步創建的對象,也就是調用其構造方法
  • 棧中的obj指向堆中的對象
  • 以上步驟看起來也是沒有問題的,畢竟創建的對象要調用完構造方法后才會被引用。

    但問題是jvm是會對指令進行重排序的,重排之后可能是第4步先于第3步執行,那這時候另外一個線程讀到的就是沒有還執行構造方法的對象,導致未知問題。jvm重排只保證重排前和重排后在單線程中的結果一致性。

    注意java中引用的賦值操作一定是原子的,比如說a和b均是對象的情況下不管是32位還是64位jvm,a=b操作均是原子的。但如果a和b是long或者double原子型數據,那在32位jvm上a=b不一定是原子的(看jvm具體實現),有可能是分成了兩個32位操作。 但是對于voliate的long,double 變量來說,其賦值是原子的。

    具體可以看這里https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7

    ?

    數據庫中讀寫一致性

    跳出hashmap,在數據庫中都是要用mvcc機制避免加讀寫鎖。也就是說如果不用mvcc,數據庫是要加讀寫鎖的,那為什么數據庫要加讀寫鎖呢?原因是寫操作不是原子的,如果不加讀寫鎖或mvcc,可能會讀到中間狀態的數據,以HBase為例,Hbase寫流程分為以下幾個步驟:
    1.獲得行鎖
    2.開啟mvcc
    3.寫到內存buffer
    4.寫到append log
    5.釋放行鎖
    6.flush log
    7.mvcc結束(這時才對讀可見)

    試想,如果沒有不走 2,7 也不加讀寫鎖,那在步驟3的時候,其他的線程就能讀到該數據。如果說3之后出現了問題,那該條數據其實是寫失敗的。也就是說其他線程曾經讀到過不存在的數據。

    同理,在mysql中,如果不用mvcc也不用讀寫鎖,一個事務還沒commit,其中的數據就能被讀到,如果用讀寫鎖,一個事務會對中更改的數據加寫鎖,這時其他讀操作會阻塞,直到事務提交,對于性能有很大的影響,所以大多數情況下數據庫都采用MVCC機制實現非鎖定讀。

    ?

    原文:Java架構筆記

    免費Java高級資料需要自己領取,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并發分布式等教程,一共30G。??????????????????
    傳送門:??????????????????https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q

    轉載于:https://www.cnblogs.com/yuxiang1/p/11270285.html

    總結

    以上是生活随笔為你收集整理的面试必问:读写一致性,你需要思考的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。