簡體   English   中英

如何使用 java 處理緩存中的鎖定 (ConcurrentHashMap)

[英]How to handle lock in cache (ConcurrentHashMap) using java

我正在使用在多個線程之間共享的concurrenthashmap設計一個緩存系統。 它也有兩個方法,get 和 put。 我無法處理一種情況。 場景是,如果多個線程要從緩存中獲取數據,並且key不可用,那么一個線程會從數據庫中獲取數據並放入緩存中(ConcurrentHashMap) 其他線程將等待直到thread-1將數據設置到緩存中,然后其他線程將從緩存中讀取數據。 我將如何實現這一目標。

提前致謝。

ConcurrentHashMap#computeIfAbsent

正如Wasserman 所評論的那樣ConcurrentHashMap class 提供了一個computeIfAbsent方法來做你想做的事。 該方法以原子方式工作以:

  • 查看 map 是否有該鍵的條目。 如果是,則返回該鍵的值。
  • 如果未找到條目,則執行您指定的 lambda function 以產生一個值。 該值作為鍵值條目存儲在 map 中。 並且,該值被返回。

所有這些工作都是原子發生的,這意味着您的 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 >

我們從AliceBob的兩個條目的 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;
        }
    }
}

請參閱在 IdeOne.com 上實時運行的代碼

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM