0

单线程版本:

private final List<Element> list = new ArrayList<Element>();

public Element getElementAt(int index) {

    if (index >= list.size()) {
        for (int i = list.size(); i <= index; i++) {
            list.add(createElement(i));
        }
    }

    return list.get(index);
}

现在我正在尝试制作一个带有双重检查锁定的线程安全版本:

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;

...

private volatile List<Element> list = ImmutableList.of();

public Element getElementAt(int index) {

    if (index >= list.size()) {

        synchronized (this) {
            if (index >= list.size()) {
                Builder<Element> newListBuilder = ImmutableList.<Element> builder();
                newListBuilder.addAll(list);
                for (int i = list.size(); i <= index; i++) {
                    newListBuilder.add(createElement(i));
                }

                list = newListBuilder.build();
            }
        }
    }

    return list.get(index);
}

这个对吗?

4

1 回答 1

0

您正在做的更像是地图/字典查找。如果您认为您的列表确实表现得像 aMap<Integer, Element>那么您可以使用并发映射的 putIfAbsent 方法来处理此问题而不会阻塞:

private final ConcurrentMap<Integer, Element> map =
                new ConcurrentHashMap<Integer, Element>();

public Element getElementAt(int index) {

    if (index >= map.size()) {
        for (int i = map.size(); i <= index; i++) {
            map.putIfAbsent(i, createElement());
        }
    }

    return map.get(index);
}

这假设对返回的元素没有特定的排序要求createElement- 尽管如果是这种情况,那么无论如何您都需要对它们的创建方式进行更严格的限制。

有可能实际上您可以简单地在此方法周围放置一个同步块(以及访问列表之外的任何其他方法)。这很容易理解,而且速度相对较快。如果获取元素不是代码的性能热点,我不想做一些“聪明”的事情只是为了减少几纳秒。

于 2013-08-15T14:28:25.040 回答