MST

星途 面试题库

面试题:Java LinkedHashMap访问顺序与性能优化

假设在一个高并发的场景下,需要频繁地访问和更新LinkedHashMap中的数据,并且要保证按照访问顺序。请分析可能会出现的问题,并阐述如何使用Java的并发工具类来优化和解决这些问题,同时给出相关代码示例。
18.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

可能出现的问题

  1. 线程安全问题LinkedHashMap本身不是线程安全的,在高并发环境下,多个线程同时进行读/写操作,可能会导致数据不一致、ConcurrentModificationException等异常。
  2. 性能问题:由于需要保证访问顺序,每次访问元素时都可能涉及到内部链表结构的调整,如果没有合理的并发控制,可能会导致频繁的锁竞争,影响性能。

使用Java并发工具类优化和解决

  1. 使用ConcurrentHashMapLinkedList模拟
    • ConcurrentHashMap提供线程安全的键值对存储。
    • LinkedList用于维护访问顺序。
  2. 使用ConcurrentLinkedHashMap:这是Guava库中的一个类,它结合了ConcurrentHashMap的线程安全性和LinkedHashMap的访问顺序特性。

代码示例

使用ConcurrentHashMapLinkedList模拟

import java.util.ConcurrentModificationException;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentLinkedHashMap<K, V> {
    private final Map<K, V> map;
    private final LinkedList<K> list;
    private final int capacity;

    public ConcurrentLinkedHashMap(int capacity) {
        this.map = new ConcurrentHashMap<>();
        this.list = new LinkedList<>();
        this.capacity = capacity;
    }

    public V get(K key) {
        V value = map.get(key);
        if (value != null) {
            synchronized (list) {
                list.remove(key);
                list.addLast(key);
            }
        }
        return value;
    }

    public void put(K key, V value) {
        if (map.size() >= capacity) {
            K oldestKey;
            synchronized (list) {
                oldestKey = list.removeFirst();
            }
            map.remove(oldestKey);
        }
        map.put(key, value);
        synchronized (list) {
            list.addLast(key);
        }
    }

    public static void main(String[] args) {
        ConcurrentLinkedHashMap<Integer, Integer> map = new ConcurrentLinkedHashMap<>(3);
        map.put(1, 1);
        map.put(2, 2);
        map.put(3, 3);
        System.out.println(map.get(2));
        map.put(4, 4);
        System.out.println(map.get(1));
    }
}

使用GuavaConcurrentLinkedHashMap

首先需要在pom.xml中添加Guava依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
</dependency>

然后是代码示例:

import com.google.common.cache.ConcurrentLinkedHashMap;
import com.google.common.cache.RemovalNotification;

public class GuavaConcurrentLinkedHashMapExample {
    public static void main(String[] args) {
        ConcurrentLinkedHashMap<Integer, Integer> map = ConcurrentLinkedHashMap
               .newBuilder()
               .maximumWeight(3)
               .weightedValue((k, v) -> 1)
               .removalListener((RemovalNotification<Integer, Integer> notification) ->
                        System.out.println("Removed: " + notification.getKey() + "=" + notification.getValue()))
               .build();
        map.put(1, 1);
        map.put(2, 2);
        map.put(3, 3);
        System.out.println(map.get(2));
        map.put(4, 4);
        System.out.println(map.get(1));
    }
}