有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

当读写器线程位于ConcurrentHashMap上时的java性能

在一次采访中,面试官问我ConcurrentHashMap与HashTable有何不同。我只想讨论一下面试官不相信的一点。我说过,在ConcurrentHashMap中,任意数量的线程都可以同时执行读取操作,而在HashTable中,一次只能执行一个线程。然后他给出了ConcurrentHashMap的一个场景,假设一个线程在一个段上写,同时另一个线程正在读取它的值,那么第二个线程会被阻塞吗??我说不,但他不相信。我查了javadoc,上面写着

检索操作(包括get)通常不会 块,因此可能与更新操作(包括put)重叠 然后移除)。检索结果反映了大多数 最近完成的更新操作保留了 起病

它说检索操作不会阻止,而是添加了generally这是什么意思

为此,我制作了一个程序,其中两个线程对ConcurrentHashMap和HashTable以及synchronizedMap执行读写操作: 我在同一段上执行读写操作一秒钟

class ReaderThread extends Thread {

    private Map<String, Integer> map;
    private static boolean b = false;

    public ReaderThread(Map<String, Integer> map) {
        this.map = map;
    }

    public void run() {
        long startTime = System.nanoTime();
        long endTime = 0;
        while (!b) {
            map.get("A");
            endTime = System.nanoTime();
            if (endTime - startTime > 1000000000L)
                b = true;
        }
    }
}

class WriterThread extends Thread {

    private Map<String, Integer> map;
    private static int n = 0;
    private static boolean b = false;

    public WriterThread(Map<String, Integer> map) {
        this.map = map;
    }

    public void run() {
        long startTime = System.nanoTime();
        long endTime = 0;
        while (!b) {
            map.put("A", n++);
            endTime = System.nanoTime();
            if (endTime - startTime > 1000000000L)
                b = true;
        }
    }
}

public class DiffrentMapReadWritePerformanceTest {
    public static void main(String[] args) throws InterruptedException {
        Map<String, Integer> map = new ConcurrentHashMap<>();
//      Map<String, Integer> map = new Hashtable<>();       
//      Map<String, Integer> map = new HashMap<>();
//      map = Collections.synchronizedMap(map);
        Thread readerThread = new ReaderThread(map);
        Thread writerThread = new WriterThread(map);

        writerThread.start();
        readerThread.start();
        writerThread.join();
        readerThread.join();
        System.out.println(map.get("A"));
    }
}

以及基于不同地图对象的O/p: ConcurrentHashMap:8649407 哈希表:5284068 同步地图:5438039

因此,输出证明ConcurrentHashMap在多线程环境中相对于HashTable是快速的,但不能证明在编写器线程写入时,读线程没有被阻塞以进行读取。有没有办法证实这一点


共 (1) 个答案

  1. # 1 楼答案

    JavaDoc注释是为类的最早版本编写的。它提供了一些实现灵活性,并允许进行改进

    在非常早期的版本中,size()会乐观地对段进行求和,但会退回到锁定来读取计数器。类似地,当缺少映射并且需要进行检查以解决可能的编译器重新排序时,也会使用readValueUnderLock。例如,Java内存模型就解决了这个问题,它同时被设计来保证编译器能做什么和不能做什么

    在Java8中,哈希表从粗段重新设计为细粒度的容器。然而computeIfAbsent总是锁定读取或计算值,因此非常悲观。在Java9中,这是通过在条目位于垃圾箱的头部时避免锁定来实现的,但如果不是,则锁定扫描。在缓存之类的情况下,这可能不够好,因此咖啡因在计算之前总是执行乐观的get。在这些情况下,这可能会提高性能

    这意味着检索时可能会发生锁定,但随着设计的发展,可能不会发生锁定以避免它。模糊的措辞允许类契约在实现更改时保留