java - 如何使用java处理缓存(ConcurrentHashMap)中的锁

标签 java multithreading caching concurrenthashmap in-memory

我正在使用在多个线程之间共享的concurrenthashmap设计一个缓存系统。它还有两个方法,get 和 put。我无法处理一种情况。场景是,如果多个线程想要从缓存中获取数据而键不可用,那么一个线程将从数据库中获取数据并将其放入缓存(ConcurrentHashMap)。其他线程将等待,直到thread-1将数据设置到缓存中,然后其他线程将从缓存中读取数据。我将如何实现这一目标。

提前致谢。

最佳答案

ConcurrentHashMap#computeIfAbsent

commented by WassermanConcurrentHashMap类(class)提供 computeIfAbsent 方法做你想做的事。该方法以原子方式工作:

  • 查看 map 上是否有该键的条目。如果是,则返回该键的值。
  • 如果未找到条目,则执行指定的 lambda 函数以生成值。该值作为键值条目存储在映射中。并且,该值被返回。

所有这些工作都是以原子方式发生的,这意味着您的 map 以线程安全的方式运行,而无需添加任何进一步的保护。

引用 Javadoc:

If the specified key is not already associated with a value, attempts to compute its value using the given mapping function and enters it into this map unless null. The entire method invocation is performed atomically.

使用代码的方法引用从数据库检索值的示例代码:

map.computeIfAbsent( myKey , key -> repository::fetchValueForKey ) ;

...或使用方法调用:

map.computeIfAbsent( myKey , key -> myRepository.fetchValueForKey( key ) ) ;

示例应用

这是一个完整的示例应用程序。

我们使用一张 map 来跟踪一周中的哪一天被分配给哪个人的名字,映射 String java.time.DayOfWeek 枚举对象,a Map< String , DayOfWeek > .

我们从 Alice 的两个条目的 map 开始& Bob 。我们的目标是找到 Carol 的第三个条目。如果未找到,请为该键添加一个值为 DayOfWeek.THURSDAY 的条目.

我们定义一个类Repository我们假设正在调用数据库来查找分配给 Carol 键的值.

我们要执行的任务定义为 Callable 返回 DayOfWeek目的。我们提交Callable多次反对执行人服务。该服务返回 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;
        }
    }
}

查看此code run live at IdeOne.com .

INFO - Before: map = {Bob=TUESDAY, Alice=MONDAY}
INFO - After: map = {Bob=TUESDAY, Alice=MONDAY, Carol=THURSDAY}
THURSDAY
THURSDAY
THURSDAY
THURSDAY
THURSDAY

关于java - 如何使用java处理缓存(ConcurrentHashMap)中的锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67449764/

相关文章:

c++ - 新线程中的launch方法

java - Javafx 是否支持启动您自己的线程?

android - 使用 Volley 和 OkHttp 时如何配置 Http 缓存?

php - 编码和缓存 gravatar 图片有什么副作用吗?

java - AbstractProcessor,如何声明哪个目标是另一个注释的注释?

java - 如何重新启用 JButton

java - 使用 ThreadLocal 为每个线程分配 ID

c# - MemoryCache OutOfMemoryException

java - 检索猫头鹰 :restrictions using the OWL API

java - 如何在 jFrame 上布局多个面板? ( java )