成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

不會這些“高級貨”,活該你面試當炮灰...

開發 架構 開發工具
今天聊一個非常硬核的技術知識,給大家分析一下 CopyOnWrite 思想是什么,以及在 Java 并發包中的具體體現,包括在 Kafka 內核源碼中是如何運用這個思想來優化并發性能的。

 今天聊一個非常硬核的技術知識,給大家分析一下 CopyOnWrite 思想是什么,以及在 Java 并發包中的具體體現,包括在 Kafka 內核源碼中是如何運用這個思想來優化并發性能的。

這個 CopyOnWrite 在面試的時候,很可能成為面試官的一個殺手锏把候選人給一擊必殺,也很有可能成為候選人拿下 Offer 的獨門秘籍,是相對高級的一個知識。

讀多寫少的場景下引發的問題?

大家可以設想一下現在我們的內存里有一個 ArrayList,這個 ArrayList 默認情況下肯定是線程不安全的,要是多個線程并發讀和寫這個 ArrayList 可能會有問題。

好,問題來了,我們應該怎么讓這個 ArrayList 變成線程安全的呢?有一個非常簡單的辦法,對這個 ArrayList 的訪問都加上線程同步的控制。

比如說一定要在 Synchronized 代碼段來對這個 ArrayList 進行訪問,這樣的話,就能同一時間就讓一個線程來操作它了,或者是用 ReadWriteLock 讀寫鎖的方式來控制,都可以。

我們假設就是用 ReadWriteLock 讀寫鎖的方式來控制對這個 ArrayList 的訪問。

這樣多個讀請求可以同時執行從 ArrayList 里讀取數據,但是讀請求和寫請求之間互斥,寫請求和寫請求也是互斥的。

大家看看,代碼大概就是類似下面這樣:

  1. public Object  read() { 
  2.     lock.readLock().lock(); 
  3.     // 對ArrayList讀取 
  4.     lock.readLock().unlock(); 
  5. public void write() { 
  6.     lock.writeLock().lock(); 
  7.     // 對ArrayList寫 
  8.     lock.writeLock().unlock(); 

大家想想,類似上面的代碼有什么問題呢?***的問題,其實就在于寫鎖和讀鎖的互斥。假設寫操作頻率很低,讀操作頻率很高,是寫少讀多的場景。

那么偶爾執行一個寫操作的時候,是不是會加上寫鎖,此時大量的讀操作過來是不是就會被阻塞住,無法執行?

這個就是讀寫鎖可能遇到的***的問題。

引入 CopyOnWrite 思想解決問題

這個時候就要引入 CopyOnWrite 思想來解決問題了。

它的思想就是,不用加什么讀寫鎖,鎖統統給我去掉,有鎖就有問題,有鎖就有互斥,有鎖就可能導致性能低下,你阻塞我的請求,導致我的請求都卡著不能執行。

那么它怎么保證多線程并發的安全性呢?很簡單,顧名思義,利用“CopyOnWrite”的方式,這個英語翻譯成中文,大概就是“寫數據的時候利用拷貝的副本來執行”。

你在讀數據的時候,其實不加鎖也沒關系,大家左右都是一個讀罷了,互相沒影響。

問題主要是在寫的時候,寫的時候你既然不能加鎖了,那么就得采用一個策略。

假如說你的 ArrayList 底層是一個數組來存放你的列表數據,那么這時比如你要修改這個數組里的數據,你就必須先拷貝這個數組的一個副本。

然后你可以在這個數組的副本里寫入你要修改的數據,但是在這個過程中實際上你都是在操作一個副本而已。

這樣的話,讀操作是不是可以同時正常的執行?這個寫操作對讀操作是沒有任何的影響的吧!

大家看下面的圖,一起來體會一下這個過程:

 

關鍵問題來了,那那個寫線程現在把副本數組給修改完了,現在怎么才能讓讀線程感知到這個變化呢?

關鍵點來了,劃重點!這里要配合上 Volatile 關鍵字的使用。

筆者之前寫過文章,給大家解釋過 Volatile 關鍵字的使用,核心就是讓一個變量被寫線程給修改之后,立馬讓其他線程可以讀到這個變量引用的最近的值,這就是 Volatile 最核心的作用。

所以一旦寫線程搞定了副本數組的修改之后,那么就可以用 Volatile 寫的方式,把這個副本數組賦值給 Volatile 修飾的那個數組的引用變量了。

只要一賦值給那個 Volatile 修飾的變量,立馬就會對讀線程可見,大家都能看到***的數組了。

下面是 JDK 里的 CopyOnWriteArrayList 的源碼:

  1. // 這個數組是核心的,因為用volatile修飾了 
  2.    // 只要把***的數組對他賦值,其他線程立馬可以看到***的數組 
  3.    private transient volatile Object[] array; 
  4.  
  5.    public boolean add(E e) { 
  6.        final ReentrantLock lock = this.lock; 
  7.        lock.lock(); 
  8.        try { 
  9.            Object[] elements = getArray(); 
  10.            int len = elements.length; 
  11.            // 對數組拷貝一個副本出來 
  12.            Object[] newElements = Arrays.copyOf(elements, len + 1); 
  13.            // 對副本數組進行修改,比如在里面加入一個元素 
  14.            newElements[len] = e; 
  15.            // 然后把副本數組賦值給volatile修飾的變量 
  16.            setArray(newElements); 
  17.            return true
  18.        } finally { 
  19.            lock.unlock(); 
  20.        } 
  21.    } 

大家看看寫數據的時候,他是怎么拷貝一個數組副本,然后修改副本,接著通過 Volatile 變量賦值的方式,把修改好的數組副本給更新回去,立馬讓其他線程可見的。

然后大家想,因為是通過副本來進行更新的,萬一要是多個線程都要同時更新呢?那搞出來多個副本會不會有問題?

當然不能多個線程同時更新了,這個時候就是看上面源碼里,加入了 Lock 鎖的機制,也就是同一時間只有一個線程可以更新。

那么更新的時候,會對讀操作有任何的影響嗎?絕對不會,因為讀操作就是非常簡單的對那個數組進行讀而已,不涉及任何的鎖。

而且只要他更新完畢對 Volatile 修飾的變量賦值,那么讀線程立馬可以看到***修改后的數組,這是 Volatile 保證的:

  1. private E get(Object[] a, int index) { 
  2.         // 最簡單的對數組進行讀取 
  3.         return (E) a[index]; 
  4.     }  

這樣就***解決了我們之前說的讀多寫少的問題。如果用讀寫鎖互斥的話,會導致寫鎖阻塞大量讀操作,影響并發性能。

但是如果用了 CopyOnWriteArrayList,就是用空間換時間,更新的時候基于副本更新,避免鎖,然后***用 Volatile 變量來賦值保證可見性,更新的時候對讀線程沒有任何的影響!

CopyOnWrite 思想在 Kafka 源碼中的運用

在 Kafka 的內核源碼中,有這么一個場景,客戶端在向 Kafka 寫數據的時候,會把消息先寫入客戶端本地的內存緩沖,然后在內存緩沖里形成一個 Batch 之后再一次性發送到 Kafka 服務器上去,這樣有助于提升吞吐量。

話不多說,大家看下圖:

 

這個時候 Kafka 的內存緩沖用的是什么數據結構呢?大家看源碼:

  1. private final ConcurrentMap<TopicPartition, Deque<RecordBatch>> batches =  
  2. new CopyOnWriteMap<TopicPartition, Deque<RecordBatch>>(); 

這個數據結構就是核心的用來存放寫入內存緩沖中的消息的數據結構,要看懂這個數據結構需要對很多 Kafka 內核源碼里的概念進行解釋,這里先不展開。

但是大家關注一點,他是自己實現了一個 CopyOnWriteMap,這個CopyOnWriteMap 采用的就是 CopyOnWrite 思想。

我們來看一下這個 CopyOnWriteMap 的源碼實現:

  1. // 典型的volatile修飾普通Map 
  2.    private volatile Map<K, V> map; 
  3.    @Override 
  4.    public synchronized V put(K k, V v) { 
  5.        // 更新的時候先創建副本,更新副本,然后對volatile變量賦值寫回去 
  6.        Map<K, V> copy = new HashMap<K, V>(this.map); 
  7.        V prev = copy.put(k, v); 
  8.        this.map = Collections.unmodifiableMap(copy); 
  9.        return prev; 
  10.    } 
  11.    @Override 
  12.    public V get(Object k) { 
  13.        // 讀取的時候直接讀volatile變量引用的map數據結構,無需鎖 
  14.        return map.get(k); 
  15.    } 

Kafka 這個核心數據結構在這里之所以采用 CopyOnWriteMap 思想來實現,就是因為這個 Map 的 Key-Value 對,其實沒那么頻繁更新。

也就是 TopicPartition-Deque 這個 Key-Value 對,更新頻率很低。

但是它的 Get 操作卻是高頻的讀取請求,因為會高頻的讀取出來一個 TopicPartition 對應的 Deque 數據結構,來對這個隊列進行入隊出隊等操作,所以對于這個 Map 而言,高頻的是其 Get 操作。

這個時候,Kafka 就采用了 CopyOnWrite 思想來實現這個 Map,避免更新 Key-Value 的時候阻塞住高頻的讀操作,實現無鎖的效果,優化線程并發的性能。

相信大家看完這個文章,對于 CopyOnWrite 思想以及適用場景,包括 JDK 中的實現,以及在 Kafka 源碼中的運用,都有了一個切身的體會了。

如果你能在面試時說清楚這個思想以及他在 JDK 中的體現,并且還能結合知名的開源項目 Kafka 的底層源碼進一步向面試官進行闡述,面試官對你的印象肯定大大的加分。

中華石杉:十余年 BAT 架構經驗,一線互聯網公司技術總監。帶領上百人團隊開發過多個億級流量高并發系統。現將多年工作中積累下的研究手稿、經驗總結整理成文,傾囊相授。微信公眾號:石杉的架構筆記(ID:shishan100)。

 

 

責任編輯:武曉燕 來源: 石杉的架構筆記
相關推薦

2016-11-09 13:52:35

Hadoop分布式集群

2022-07-05 08:34:48

HttpBasic認證模式

2020-04-07 12:14:51

Zookeeper數據模型

2015-03-16 11:33:16

程序員代碼bug

2023-11-03 12:56:47

PythonGUI

2021-05-18 08:02:40

面試面試問題職業規劃

2020-04-20 08:35:48

HTTP HTTPS網絡協議

2023-08-27 21:47:15

2020-10-14 09:04:18

Kafka系統通信

2020-08-12 09:45:23

SQL優化技巧

2020-04-16 10:02:47

獵豹移動谷歌下架

2015-03-12 13:36:27

程序猿導火索華爾街

2022-07-26 19:06:16

Linux命令MacOS

2019-12-02 08:27:43

Dubbo高并發分布式

2018-07-25 14:27:43

Redis數據架構存儲

2025-02-27 07:47:09

2022-06-15 23:35:04

元宇宙電商Web3.0

2015-10-28 17:35:51

資本

2015-11-10 09:28:23

程序員需求
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级毛片免费完整视频 | 国产亚洲精品久久情网 | 无码一区二区三区视频 | 99在线播放 | 成人毛片一区二区三区 | 国产最好的av国产大片 | 日韩一级黄色片 | 国产99久久 | 国产999精品久久久 日本视频一区二区三区 | 日日噜| 中文字幕一区在线观看视频 | 日本精品一区二区三区在线观看视频 | 国产亚洲二区 | 中国美女一级黄色片 | 日韩中文字幕 | 国产视频观看 | 欧美伊人| 六月婷婷久久 | 亚洲www啪成人一区二区 | 欧美精品一区二区三区在线 | 99精品国产一区二区三区 | 狠狠插狠狠操 | 人妖一区 | 久久精品久久久久久 | 亚洲最大成人综合 | 蜜桃视频在线观看免费视频网站www | 国产麻豆乱码精品一区二区三区 | 一区二区免费 | 一区二区三区福利视频 | 久久国产精品网 | 国产 日韩 欧美 制服 另类 | 亚洲天堂999| 午夜视频免费在线观看 | 国产日韩一区二区三免费 | 色婷婷亚洲一区二区三区 | 久久国内精品 | 久久精品国产亚洲 | 91免费观看 | 91久久久久久久久久久久久 | 精品国产一区二区国模嫣然 | 青青青伊人 |