淺析Java如何在并發(fā)環(huán)境下生成一個只讀的map
前言
在日常開發(fā)過程中,我們經(jīng)常會遇到一些資源初始化的情況,往往有些資源就是那種我初始化以后我們就不希望被改動,但是我們又擔(dān)心別人使用的時候不小心改動了,這時候我就在想,要是我們的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);
}
練習(xí)時長兩年半左右的Java練習(xí)生應(yīng)該知道,這樣做的好處是由靜態(tài)代碼塊在Java虛擬機中的執(zhí)行時機所決定的,下面給大伙呱唧一下!
靜態(tài)代碼塊在Java中如何執(zhí)行
在Java中,靜態(tài)代碼塊由類加載器在加載類的過程中執(zhí)行。當(dāng)類被第一次加載時,類加載器會執(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)文章
SpringBoot+netty-socketio實現(xiàn)服務(wù)器端消息推送
這篇文章主要介紹了SpringBoot+netty-socketio實現(xiàn)服務(wù)器端消息推送,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Java實現(xiàn)將PDF轉(zhuǎn)為PDF/A
通過將PDF格式轉(zhuǎn)換為PDF/A格式,可保護文檔布局、格式、字體、大小等不受更改,從而實現(xiàn)文檔安全保護的目的,同時又能保證文檔可讀、可訪問。本文將為大家介紹如何實現(xiàn)這一轉(zhuǎn)換,需要的可以參考一下2022-01-01
詳解Java設(shè)計模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu)
這篇文章主要介紹了Java設(shè)計模式編程中的Flyweight享元模式的開發(fā)結(jié)構(gòu),享元模式能夠最大限度地重用現(xiàn)有的同類對象,需要的朋友可以參考下2016-04-04
淺談synchronized方法對非synchronized方法的影響
下面小編就為大家?guī)硪黄獪\談synchronized方法對非synchronized方法的影響。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
java控制臺實現(xiàn)學(xué)生信息管理系統(tǒng)(IO版)
這篇文章主要為大家詳細(xì)介紹了java控制臺實現(xiàn)學(xué)生信息管理系統(tǒng)(IO版),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-04-04

