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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

写缓存java,编写线程安全的Java缓存读写机制 (原创)

發(fā)布時間:2025/5/22 java 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 写缓存java,编写线程安全的Java缓存读写机制 (原创) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一種習(xí)以為常的緩存寫法:

IF value in cached THEN

return value from cache

ELSE

compute value

save value in cache

return value

END IF

看上去邏輯無比正確,但實際上會造成2種問題:

1、這種方法是不線程安全的。

2、產(chǎn)生數(shù)值寫入重復(fù),造成錯誤的數(shù)據(jù)。

如下圖,在線程1執(zhí)行計算數(shù)值的過程中,線程2也進入數(shù)據(jù)檢查,將多次寫入數(shù)據(jù),程序非常危險。

演示錯誤代碼:

//最容易產(chǎn)生的錯誤寫法,先讀取緩存,讀不到就寫緩存

public Long getNumber(final long index) {

if (cache.containsKey(index)) {

return cache.get(index);

}

final long value = getNumber(index - ) + getNumber(index - );

cache.put(index, value);

return value;

}

1、傳統(tǒng)的解決辦法,使用重入鎖 (getNumberByLock 方法)或者同步鎖(getNumberBySynchroniz 方法)。

代碼

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class NaiveCacheExample {

private final Map cache = new HashMap<>();

private Object o=new Object();

Lock lock =new ReentrantLock();

public NaiveCacheExample() {

cache.put(0L, 1L);

cache.put(1L, 1L);

}

//最容易產(chǎn)生的錯誤寫法,先讀取緩存,讀不到就寫緩存

public Long getNumber(final long index) {

if (cache.containsKey(index)) {

return cache.get(index);

}

final long value = getNumber(index - ) + getNumber(index - );

cache.put(index, value);

return value;

}

//使用折返鎖,使讀寫同步

public Long getNumberByLock(final long index) {

long value =;

try {

lock.lock();

if (cache.containsKey(index)) {

return cache.get(index);

}

value = getNumberByLock(index - ) + getNumberByLock(index - );

cache.put(index, value);

return value;

}

catch (Exception e)

{}

finally

{

lock.unlock();

}

return 0l;

}

//使用同步,使讀寫同步

public Long getNumberBySynchroniz(final long index) {

synchronized (o)

{

long value =;

try {

if (cache.containsKey(index)) {

return cache.get(index);

}

value = getNumberBySynchroniz(index - ) + getNumberBySynchroniz(index - );

cache.put(index, value);

return value;

}

catch (Exception e)

{}

finally

{

}

}

return 0l;

}

public static void main(final String[] args) {

NaiveCacheExample naiveCacheExample =new NaiveCacheExample();

Thread threadA =new Thread(new Runnable()

{

@Override

public void run() {

System.out.println(naiveCacheExample.getNumberBySynchroniz());

}

}

,"Thread-A");

threadA.start();

final Thread threadB = new Thread(new Runnable() {

public void run() {

System.out.println(naiveCacheExample.getNumberBySynchroniz());

}

}, "Thread-B");

threadB.start();

}

}

2、一個更好的緩存算法可以用?Callable?和 Future?。 緩存的值將存儲在一個實例 ConcurrentMap 中 ,ConcurrentMap 是線程安全的。

代碼:

import java.util.concurrent.Callable;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.ConcurrentMap;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.Future;

import java.util.concurrent.FutureTask;

public class GenericCacheExample {

private final ConcurrentMap> cache = new ConcurrentHashMap<>();

private Future createFutureIfAbsent(final K key, final Callable callable) {

Future future = cache.get(key);

if (future == null) {

final FutureTask futureTask = new FutureTask(callable);

future = cache.putIfAbsent(key, futureTask);

if (future == null) {

future = futureTask;

futureTask.run();

}

}

return future;

}

public V getValue(final K key, final Callable callable) throws InterruptedException, ExecutionException {

try {

final Future future = createFutureIfAbsent(key, callable);

return future.get();

} catch (final InterruptedException e) {

cache.remove(key);

throw e;

} catch (final ExecutionException e) {

cache.remove(key);

throw e;

} catch (final RuntimeException e) {

cache.remove(key);

throw e;

}

}

public void setValueIfAbsent(final K key, final V value) {

createFutureIfAbsent(key, new Callable() {

@Override

public V call() throws Exception {

return value;

}

});

}

}

參考博客:

http://www.javacreed.com/how-to-cache-results-to-boost-performance/

Java緩存機制

1 Java緩存 1.1 jvm內(nèi)置緩存 Java中實現(xiàn)緩存的方式有很多,比如用static hashMap基于內(nèi)存緩存的jvm內(nèi)置緩存,簡單不實用,保對象的有效性和周期無法控制,容易造成內(nèi)存急劇上升 ...

Java的多線程機制系列:&lpar;二)緩存一致性和CAS

一.總線鎖定和緩存一致性 這是兩個操作系統(tǒng)層面的概念.隨著多核時代的到來,并發(fā)操作已經(jīng)成了很正常的現(xiàn)象,操作系統(tǒng)必須要有一些機制和原語,以保證某些基本操作的原子性.首先處理器需要保證讀一個字節(jié)或?qū)懸粋€ ...

并發(fā)讀寫緩存實現(xiàn)機制&lpar;一&rpar;:為什么ConcurrentHashMap可以這么快?

大家都知道ConcurrentHashMap的并發(fā)讀寫速度很快,但為什么它會這么快?這主要歸功于其內(nèi)部數(shù)據(jù)結(jié)構(gòu)和獨特的hash運算以及分離鎖的機制.做游戲性能很重要,為了提高數(shù)據(jù)的讀寫速度,方法之一就 ...

Java緩存學(xué)習(xí)之二:瀏覽器緩存機制

瀏覽器端的九種緩存機制介紹 瀏覽器緩存是瀏覽器端保存數(shù)據(jù)用于快速讀取或避免重復(fù)資源請求的優(yōu)化機制,有效的緩存使用可以避免重復(fù)的網(wǎng)絡(luò)請求和瀏覽器快速地讀取本地數(shù)據(jù),整體上加速網(wǎng)頁展示給用戶.瀏覽器端緩存 ...

利用java反射機制編寫solr通用的java客戶端

一.前言 通過上一篇的講解,我們知道了dynamicFiled字段,它是動態(tài)的,不需要顯示的聲明.而且一些常用的基本類型solr已經(jīng)默認給我們創(chuàng)建好了. 例如:*_i,*_is,等. 如果我們要使用動 ...

java并發(fā)之線程同步(synchronized和鎖機制)

使用synchronized實現(xiàn)同步方法 使用非依賴屬性實現(xiàn)同步 在同步塊中使用條件(wait(),notify(),notifyAll()) 使用鎖實現(xiàn)同步 使用讀寫鎖實現(xiàn)同步數(shù)據(jù)訪問 修改鎖的公平 ...

Map實現(xiàn)java緩存機制的簡單實例

緩存是Java中主要的內(nèi)容,主要目的是緩解項目訪問數(shù)據(jù)庫的壓力以及提升訪問數(shù)據(jù)的效率,以下是通過Map實現(xiàn)java緩存的功能,并沒有用cache相關(guān)框架. 一.緩存管理類 CacheMgr.java ...

Java的多線程機制系列:不得不提的volatile及指令重排序&lpar;happen-before&rpar;

一.不得不提的volatile volatile是個很老的關(guān)鍵字,幾乎伴隨著JDK的誕生而誕生,我們都知道這個關(guān)鍵字,但又不太清楚什么時候會使用它:我們在JDK及開源框架中隨處可見這個關(guān)鍵字,但并發(fā)專 ...

Java線程新特征——Java并發(fā)庫

一.線程池 ??Sun在Java5中,對Java線程的類庫做了大量的擴展,其中線程池就是Java5的新特征之一,除了線程池之外,還有很多多線程相關(guān)的內(nèi)容,為多線程的編程帶來了極大便利.為了編寫高效穩(wěn)定 ...

隨機推薦

深入理解javascript原型和閉包(11)——執(zhí)行上下文棧

繼續(xù)上文的內(nèi)容. 執(zhí)行全局代碼時,會產(chǎn)生一個執(zhí)行上下文環(huán)境,每次調(diào)用函數(shù)都又會產(chǎn)生執(zhí)行上下文環(huán)境.當(dāng)函數(shù)調(diào)用完成時,這個上下文環(huán)境以及其中的數(shù)據(jù)都會被消除,再重新回到全局上下文環(huán)境.處于活動狀態(tài)的執(zhí)行 ...

JSON跨域請求

原理:首先客戶機會注冊一個callback,在發(fā)送跨域請求之前,會在url后附帶注冊的callback參數(shù)(如:callback1982342322),隨后服務(wù)器拿到了callback參數(shù),獲取數(shù)據(jù)后 ...

詳解Win2003 IIS6&period;0 301重定向帶參數(shù)的問題(轉(zhuǎn)摘)

網(wǎng)站更換域名,把舊域名用301指到新域名來. 從iis中設(shè)置url永久轉(zhuǎn)向就可以,看上去很容易,用了一會兒才發(fā)現(xiàn),參數(shù)都沒有帶上. 從微軟網(wǎng)站上找到如下說明,果然好使: 重定向參考 (IIS 6. ...

&lpar;轉(zhuǎn)&rpar;Server Tomcat v6&period;0 Server at localhost was unable to start within 45 seconds

仰天長嘯 Server Tomcat v6.0 Server at localhost was unable to start within 45 seconds... 當(dāng)啟動tomcat時候出現(xiàn)?S ...

jQuery extend函數(shù)詳解

一 jQuery的擴展方法原型是 $.extend(dest,src1,src2,src3); 含義是將src1,src2,src3合并到dest中,返回值為合并后的dest,該方法合并后,dest的 ...

201771010141 周強《面向?qū)ο笤O(shè)計 java》第十五周實驗總結(jié)

理論部分 ? JAR文件? 應(yīng)用程序首選項存儲? Java Web Start JAR文件: 1.Java程序的打包:程序編譯完成后,程序員將.class文件壓縮打包為.jar文件后,GUI界面程序就 ...

Modbus通信協(xié)議 【 初識 Modbus】

Modbus協(xié)議 ? ? Modbus 協(xié)議是應(yīng)用于電子控制器上的一種通用語言.通過此協(xié)議,控制器相互之間.控制器經(jīng)由網(wǎng)絡(luò)(例如以太網(wǎng))和其它設(shè)備之間可以通信.它已經(jīng)成為一通用工業(yè)標(biāo)準(zhǔn).有了它,不同廠 ...

【逆向知識】裸函數(shù)&lpar;Naked函數(shù)&rpar;

1 說明 指定裸函數(shù)編寫的函數(shù),編譯器生成不帶任何多余代碼. 利用此功能,可以使用內(nèi)聯(lián)匯編程序代碼編寫自己的 prolog/epilog 代碼序列. 裸函數(shù)對于編寫虛擬設(shè)備驅(qū)動程序特別有用. 2 練習(xí) ...

Windows XP Manifest in Delphi

Find out how you can include the manifest into a Delphi project to allow your application to share t ...

關(guān)于CentOS 6下Hadoop占用系統(tǒng)態(tài)CPU高的處理辦法【轉(zhuǎn)】

一次不經(jīng)意發(fā)現(xiàn)Hadoop的系統(tǒng)態(tài)CPU使用率很高,然后百度一下居然是個已知問題. RHEL6優(yōu)化了內(nèi)存申請的效率,而且在某些場景下對KVM的性能有明顯提升:http://www.Linux-kvm. ...

總結(jié)

以上是生活随笔為你收集整理的写缓存java,编写线程安全的Java缓存读写机制 (原创)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。