[英]How to handle lock in cache (ConcurrentHashMap) using java
我正在使用在多個線程之間共享的concurrenthashmap
設計一個緩存系統。 它也有兩個方法,get 和 put。 我無法處理一種情況。 場景是,如果多個線程要從緩存中獲取數據,並且key不可用,那么一個線程會從數據庫中獲取數據並放入緩存中(ConcurrentHashMap)
。 其他線程將等待直到thread-1
將數據設置到緩存中,然后其他線程將從緩存中讀取數據。 我將如何實現這一目標。
提前致謝。
ConcurrentHashMap#computeIfAbsent
正如Wasserman 所評論的那樣, ConcurrentHashMap
class 提供了一個computeIfAbsent
方法來做你想做的事。 該方法以原子方式工作以:
所有這些工作都是原子發生的,這意味着您的 map 以線程安全的方式運行,您無需添加任何進一步的保護。
引用 Javadoc:
如果指定的鍵尚未與值關聯,則嘗試使用給定的映射 function 計算其值,並將其輸入到此 map 中,除非 null。 整個方法調用以原子方式執行。
示例代碼使用代碼的方法引用從數據庫中檢索值:
map.computeIfAbsent( myKey , key -> repository::fetchValueForKey ) ;
…或使用方法調用:
map.computeIfAbsent( myKey , key -> myRepository.fetchValueForKey( key ) ) ;
這是一個完整的示例應用程序。
我們使用 map 跟蹤哪個星期幾分配給哪個人的姓名,將String
映射到java.time.DayOfWeek
枚舉 ZA8CFDE6331BD59EB2AC96F8911C4OfWeek Map< String, DayOfWeek >
我們從Alice
和Bob
的兩個條目的 map 開始。 我們的目標是為Carol
找到第三個條目。 如果未找到,請為該鍵添加一個值為DayOfWeek.THURSDAY
的條目。
我們定義了一個 class Repository
,我們假裝它正在調用數據庫以查找分配給Carol
鍵的值。
我們要執行的任務被定義為一個返回DayOfWeek
object 的Callable
。 我們將Callable
object 多次提交給執行器服務。 該服務返回Future
對象,我們可以通過這些對象跟蹤成功並檢索我們的結果(我們希望它是DayOfWeek.THURSDAY
對象)。
為了顯示結果,我們將Map
連同每個Future
的結果一起轉儲到控制台。
package work.basil.demo.threadmark;
import java.time.DayOfWeek;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
public class MapApp
{
public static void main ( String[] args )
{
MapApp app = new MapApp();
app.demo();
}
private void demo ( )
{
Map < String, DayOfWeek > inputs =
Map.of(
"Alice" , DayOfWeek.MONDAY ,
"Bob" , DayOfWeek.TUESDAY
);
ConcurrentMap < String, DayOfWeek > map = new ConcurrentHashMap <>( inputs );
System.out.println( "INFO - Before: map = " + map );
Repository repository = new Repository();
ExecutorService executorService = Executors.newCachedThreadPool();
Callable < DayOfWeek > task = ( ) -> { return map.computeIfAbsent( "Carol" , ( String personNameKey ) -> {return repository.fetchDayOfWeekForPersonName( personNameKey ); } ); };
List < Callable < DayOfWeek > > tasks = List.of( task , task , task , task , task );
List < Future < DayOfWeek > > futures = List.of();
try
{
futures = executorService.invokeAll( tasks );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
executorService.shutdown();
try { executorService.awaitTermination( 10 , TimeUnit.SECONDS ); } catch ( InterruptedException e ) { e.printStackTrace(); }
System.out.println( "INFO - After: map = " + map );
futures.stream().forEach( dayOfWeekFuture -> {
try
{
System.out.println( dayOfWeekFuture.get() );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
catch ( ExecutionException e )
{
e.printStackTrace();
}
} );
}
class Repository
{
public DayOfWeek fetchDayOfWeekForPersonName ( final String personName )
{
return DayOfWeek.THURSDAY;
}
}
}
INFO - Before: map = {Bob=TUESDAY, Alice=MONDAY}
INFO - After: map = {Bob=TUESDAY, Alice=MONDAY, Carol=THURSDAY}
THURSDAY
THURSDAY
THURSDAY
THURSDAY
THURSDAY
您可以使用java.util.concurrent
package 提供的ReadWriteLock
。
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
...
void write() {
readWriteLock.writeLock().lock();
try {
// read from db and write to cache
}
finally {
readWriteLock.writeLock().unlock();
}
}
void read() {
readWriteLock.readLock().lock();
try {
// read from cache or from the db
}
finally {
readWriteLock.readLock().unlock();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.