淺析Java如何在并發(fā)環(huán)境下生成一個只讀的map
前言
在日常開發(fā)過程中,我們經(jīng)常會遇到一些資源初始化的情況,往往有些資源就是那種我初始化以后我們就不希望被改動,但是我們又擔心別人使用的時候不小心改動了,這時候我就在想,要是我們的JDK能提供一種不能被修改的容器改有多好,好死不死,jdk中還真有這樣的容器,map和list都有,這里以map為例子給大家講解一下!
一般用法
在項目中一些不被改變的資源,通常采用靜態(tài)代碼塊的形式去初始化,如下:
private static Map<Integer, String> readOnlyMap;
static {
Map<Integer, String> callTimesMap = new HashMap<>();
callTimesMap.put(1, "一呼");
callTimesMap.put(2, "二呼");
callTimesMap.put(3, "三呼");
callTimesMap.put(4, "四呼");
callTimesMap.put(5, "五呼");
callTimesMap.put(6, "六呼");
callTimesMap.put(7, "七呼");
callTimesMap.put(8, "八呼");
callTimesMap.put(9, "九呼");
callTimesMap.put(10, "十呼");
readOnlyMap = Collections.unmodifiableMap(callTimesMap);
}
練習時長兩年半左右的Java練習生應該知道,這樣做的好處是由靜態(tài)代碼塊在Java虛擬機中的執(zhí)行時機所決定的,下面給大伙呱唧一下!
靜態(tài)代碼塊在Java中如何執(zhí)行
在Java中,靜態(tài)代碼塊由類加載器在加載類的過程中執(zhí)行。當類被第一次加載時,類加載器會執(zhí)行其中的靜態(tài)代碼塊,并且只會執(zhí)行一次。
創(chuàng)建只讀的容器
要創(chuàng)建只讀的容器其實也很簡單:
Collections.unmodifiableMap(callTimesMap);
這樣就可以實現(xiàn)了!
測試證明
public static void main(String[] args) {
//模擬并發(fā)環(huán)境
new Thread(()->{
readOnlyMap.put(11,"s");
}).start();
readOnlyMap.put(11,"s");
}測試結(jié)果:
Exception in thread "Thread-0" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableMap.put(Collections.java:1459)
at com.zhuiyi.yicall.callout.statistic.impl.SessionStatisticServiceImpl.lambda$main$0(SessionStatisticServiceImpl.java:94)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableMap.put(Collections.java:1459)
at com.zhuiyi.yicall.callout.statistic.impl.SessionStatisticServiceImpl.main(SessionStatisticServiceImpl.java:96)
我們可以看到“Thread-0”和"main"線程都拋出了異常!這說明在并發(fā)條件下確實不允許寫,只允許讀!
只讀容器的底層實現(xiàn)原理
直接上源碼:
private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
private static final long serialVersionUID = -1034234728574286014L;
private final Map<? extends K, ? extends V> m;
UnmodifiableMap(Map<? extends K, ? extends V> m) {
if (m==null)
throw new NullPointerException();
this.m = m;
}
public int size() {return m.size();}
public boolean isEmpty() {return m.isEmpty();}
public boolean containsKey(Object key) {return m.containsKey(key);}
public boolean containsValue(Object val) {return m.containsValue(val);}
public V get(Object key) {return m.get(key);}
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
public V remove(Object key) {
throw new UnsupportedOperationException();
}
public void putAll(Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
//.....此處省略很多代碼
}
從源碼中我們可以看出,UnmodifiableMap實現(xiàn)了map接口,所以它具有map的所有功能,同時最最重要的是他將所有會動到容器中的數(shù)據(jù)的方法都拋出異常了!
如下:
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
public V remove(Object key) {
throw new UnsupportedOperationException();
}
public void putAll(Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
這樣就從源頭上控制了容器不支持寫,只支持讀!
思考:針對這樣的場景,是否還有別的實現(xiàn)方式?
答案肯定是有的,我們可以使用一個全局鎖,或者分布式鎖都能實現(xiàn)!
全局讀鎖:
ReadWriteLock lock = new ReentrantReadWriteLock();
public void readData() {
lock.readLock().lock();
try {
// 執(zhí)行讀取操作callTimesMap
} finally {
lock.readLock().unlock();
}
}
如果使用分布式鎖或者全局鎖的話性能會變差,所以最好的解決方案就是直接創(chuàng)建一個不能被修改的容器,這樣效率是最高,也是最安全的!
到此這篇關(guān)于淺析Java如何在并發(fā)環(huán)境下生成一個只讀的map的文章就介紹到這了,更多相關(guān)Java并發(fā)生成只讀map內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring學習筆記之RestTemplate使用小結(jié)
這篇文章主要給大家介紹了關(guān)于Spring學習筆記之RestTemplate使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-08-08
Elasticsearch算分優(yōu)化方案之rescore_query示例詳解
這篇文章主要為大家介紹了Elasticsearch算分優(yōu)化方案之rescore_query示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08
SpringBoot利用觀察者模式實現(xiàn)聯(lián)動更新機制
觀察者模式(Observer Pattern)是一種軟件設計模式,在許多應用系統(tǒng)中,我們經(jīng)常需要處理多個表之間的關(guān)聯(lián)更新問題,本文將通過一個具體的案例,介紹如何在Spring Boot項目中利用觀察者模式來優(yōu)雅地解決這一需求,需要的朋友可以參考下2024-07-07
FeignMultipartSupportConfig上傳圖片配置方式
這篇文章主要介紹了FeignMultipartSupportConfig上傳圖片配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

