微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

我使用 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,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;
    }
}

设置和获取like的调用方法

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 可能会更好。

还要检查您的 hashCodeequals 实施

,

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。