单线程版本:
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);
}
这是对的吗?
答案 0 :(得分:0)
您正在做的更像是地图/字典查找。如果你认为你的列表真的像Map<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
返回的元素没有特定的排序要求 - 但如果是这种情况,那么无论如何都需要对它们的创建方式有更严格的约束。
虽然实际上你可以简单地在这个方法周围粘贴一个同步块(除了访问列表之外)。这很容易理解,而且速度相对较快。如果获取元素不是代码的性能热点,我不想做一些“聪明”的事情只是为了减少几纳秒。