Java中同步的哈希映射表只读访问

4

在Java中,有3个线程想要访问(只读)一个不可变的哈希映射以执行某些操作。以下的SynchronizedMap类是最快的解决方案吗?如果不是,那么什么会更快?

import com.carrotsearch.hppc.IntObjectMap;
import com.carrotsearch.hppc.IntObjectOpenHashMap;

public class abc {
    public static void main(String[] args) {

        final IntObjectMap<int[]> map = new IntObjectOpenHashMap<int[]>();
        for (int i = 0; i < 4; i++) {
            map.put(i, new int[] {1, 2, 3, 4, 5});
        }

        Thread[] threads = new Thread[3];

        class SynchronizedMap {

            private final Object syncObject = new Object();

            public final int[] read(int i) {

                final int[] value;

                synchronized (syncObject) {

                    // code that reads-only immutable map object
                    value = map.get(i);

                }

                return value;

            }
        }

        final SynchronizedMap syncMap = new SynchronizedMap();

        class AccessMap implements Runnable {

            private int id;
            AccessMap(int index) { id = index; }

            public void run() {

                // code that reads-only immutable map object like this:
                for (int i = 0; i < 4; i++) {

                    final int[] array = syncMap.read(i);

                    for (int j = 0; j < array.length; j++)
                        System.out.println(id + ": " + array[j] + " ");

                }

            }
        }

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(new AccessMap(i) {});
            threads[i].start();
        }

        for (int i = 0; i < threads.length; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

2
如果地图是只读的,我认为您根本不需要进行任何同步。 - Louis Wasserman
1个回答

5

下面的SynchronizedMap类是最快的解决方案吗?

不是。如果HashMap是真正的不可变/只读,则使用volatile Map<...>是最好的选择。

volatile IntObjectMap<int[]> readOnlyMap = new IntObjectOpenHashMap<int[]>();

如果您在构建地图之后才启动线程,则根本不需要volatile。唯一需要使用volatile的情况是,如果您正在交换当前正在运行的线程访问的新地图。

final IntObjectMap<int[]> readOnlyMap = new IntObjectOpenHashMap<int[]>();

我同意。这里有一个很好的讨论:http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html - paulsm4
好观点 @SophieSperner。这更多是为了记录而不是针对你的具体实现。 - Gray
回到Louis Wasserman的问题 - 如果什么都不会改变...那么为什么需要“synchronized”或“volatile”? - paulsm4
如果您正在创建一个已经运行的线程共享的新HashMap,则需要使用volatile。这涉及到操作顺序和构造函数可见性。在她的情况下,她是在创建线程之后创建HashMap,因此不需要同步。@paulsm4 - Gray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接