0

我正在编写用于文本处理的代码,如果我先将字符串转换为整数,事情会变得更快为此,我创建了一个 Dictionary 类,每次我看到一个新字符串时,我都会给它一个索引,并保留两个映射,一个从 string 到 int,一个从 int 到 string,所以我可以轻松地查找两种方式. 这是代码:

class Dictionary {
    private Map<String, Integer> map;
    private Map<Integer, String> reverse_map;
    private int nextIndex;

    public Dictionary() {
        map = new HashMap<String, Integer>();
        reverse_map = new HashMap<Integer, String>();
        nextIndex = 1;
    }

    public int getIndex(String string) {
        if (!map.containsKey(string)) {
            map.put(string, nextIndex);
            reverse_map.put(nextIndex, string);
            nextIndex++;
        }
        return map.get(string);
    }

    public String getString(int index) {
        // getIndex is always called first, so we don't need to check anything
        return reverse_map.get(index);
    }
}

在我的单线程代码中,这对我来说效果很好。但现在我想给这个多个线程以加快速度,我不知道该怎么做。我想过使用 ConcurrentHashMap,但我不确定这putIfAbsent是否能保证我不会使用索引两次。我不想使用 Collections.synchronizedMap,因为这个字典在线程之间被非常频繁地访问,所以我可能不会比使用单个线程更好,因为它在每次读取和写入时都会阻塞。有没有办法使这项工作?

4

2 回答 2

1

您对并发解决方案的问题是原子性。这些是我的想法:

private final ConcurrentMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
private final ConcurrentMap<Integer, String> reverse_map = new ConcurrentHashMap<Integer, String>();
private final AtomicInteger nextIndex = new AtomicInteger(1);

public int getIndex(String string) {
  Integer i = map.get(string);
  if (i == null) {
    final Integer newI = nextIndex.getAndIncrement();
    i = map.putIfAbsent(string, newI);
    if (i == null) {
      reverse_map.put(newI, string);
      return newI;
    }
  }
  return i;
}

这有一个非常良性的故障模式:一些索引将未被使用。

请注意,我无条件地放入第二张地图,因为此时我知道我负责手头的字符串。

于 2012-07-13T19:30:45.297 回答
1

最简单的事情是只标记您的两个方法(getIndexgetStringsynchronized。看看你得到什么样的加速。也许就足够了。

要使用ConcurrentHashMap,你可以试试这个:

private AtomicInteger nextIndex;
public int getIndex(String string) {
    Integer n = map.get(string);
    if (n == null) {
        int idx = nextIndex.getAndIncrement();
        n = map.putIfAbsent(string, idx);
        if (n != null) return n;
        reverse_map.put(idx, string);
        return idx;
    }
    return n;
}

如果两个线程同时插入相同的字符串,这可能偶尔会跳过索引,但不会经常发生。

于 2012-07-13T19:32:52.597 回答