java:在多线程中从 TreeMap 访问值时出现问题

java: issue while access value from TreeMap in multithreading

我已经使用 TreeMap 来存储键值。 对于使用自定义对象的键。 但是一旦遇到非常奇怪的问题,我就无法获得我之前设置的值(使用相同的密钥)。 下面是我的代码

public final class TestOptions implements Cloneable {   
    private Map<StorageSystemOptionKey, Object> options = new TreeMap<StorageSystemOptionKey, Object>();
private static final class StorageSystemOptionKey implements Comparable<StorageSystemOptionKey> {
    /** Constant used to create hashcode */
    private static final int HASH = 31;

    private final Class<? extends StorageRepository> storageRepositoryClass;

    /** The option name */
    private final String name;

    private StorageSystemOptionKey(Class<? extends StorageRepository> storageRepositoryClass, String name) {
        this.storageRepositoryClass = storageRepositoryClass;
        this.name = name;
    }

    public int compareTo(StorageSystemOptionKey o) {
        int ret = storageRepositoryClass.getName().compareTo(o.storageRepositoryClass.getName());
        if (ret != 0) {
            return ret;
        }
        return name.compareTo(o.name);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        final StorageSystemOptionKey that = (StorageSystemOptionKey) o;

        if (!storageRepositoryClass.equals(that.storageRepositoryClass)) {
            return false;
        }
        if (!name.equals(that.name)) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int result;
        result = storageRepositoryClass.hashCode();
        result = HASH * result + name.hashCode();
        return result;
    }

    }

    void setOption(Class<? extends StorageRepository> fileSystemClass, String name, Object value) {
        options.put(new StorageSystemOptionKey(fileSystemClass, name), value);
    }

    Object getOption(Class<? extends StorageRepository> fileSystemClass, String name) {
        StorageSystemOptionKey key = new StorageSystemOptionKey(fileSystemClass, name);
        return options.get(key);
    }

    boolean hasOption(Class<? extends StorageRepository> fileSystemClass, String name) {
        StorageSystemOptionKey key = new StorageSystemOptionKey(fileSystemClass, name);
        return options.containsKey(key);
    }

    public int compareTo(TestOptions other) {
        if (this == other) {
            return 0;
        }

        int propsSz = options == null ? 0 : options.size();
        int propsFkSz = other.options == null ? 0 : other.options.size();
        if (propsSz < propsFkSz) {
            return -1;
        }
        if (propsSz > propsFkSz) {
            return 1;
        }
        if (propsSz == 0) {
            return 0;
        }

        int hash = options.hashCode();
        int hashFk = other.options.hashCode();
        if (hash < hashFk) {
            return -1;
        }
        if (hash > hashFk) {
            return 1;
        }
        return 0;
    }

    @Override
    public Object clone() {
        TestOptions clone = new TestOptions();
        clone.options = new TreeMap<StorageSystemOptionKey, Object>(options);
        return clone;
    }
}

调用方法设置和获取点赞

public abstract Class<? extends StorageRepository> getStorageRepositoryClass();


public Class<? extends StorageRepository> getStorageRepositoryClass() {
        return MyImpl.class;
}
TestOptions opt =new TestOptions(); // shared accross all Threads
Object getProperty(String name) {
    return opt.getOption(getStorageRepositoryClass(),  name);       
}
 void setProperty(String name, Object value) {
        opt.setOption(getStorageRepositoryClass(), name, value);
    }

在多线程应用程序中使用set 和get 方法。 查询:
我多次调用 set/get 然后我也无法获得之前设置的值(相同的键)
这是因为 Treeset 实现不同步 或者 hashCodeequalscompareTo 方法实现有问题?

TreeSet 未同步。我相信 ConcurrentSkipListMap 可能会更好。

同时检查您的 hashCode, equals 实现

快速浏览一下,您的 compareTo()equals()hashCode() 看起来不错。请注意,TreeMap 将主要使用 compareTo() 来查找元素,因此该方法需要正确(您的方法在技术上看起来是正确的)。

但是,TreeMapTreeSet(以及其他基本集合和映射)不是线程安全的,因此并发修改可能会导致各种意外行为。我们曾经遇到过这样的情况,其中 2 个线程试图将单个元素添加到 hashmap,并且线程最终陷入无限循环,因为解决冲突的内部列表产生了一个循环(由于并发 put)。

因此要么使用 ConcurrentXxxx 地图和集合,要么同步访问您的地图和集合。