我在实现非重复并发ArrayList(或div#users-contain table th {
border: 9px solid #eee;
padding: .6em 120px;
}
div#users-contain table td {
border: 9px solid #eee;
padding: .6em 220px .6em 20px ;
}
)的数据结构时遇到了性能问题。
ConcurrentLinkedQueue
请注意,public class NonDuplicateList implements Outputable {
private Map<Term, Integer> map;
private List<Term> terms;
public NonDuplicateList() {
this.map = new HashMap<>();
this.terms = new ArrayList<>();
}
public synchronized int addTerm(Term term) { //bad performance :(
Integer index = map.get(term);
if (index == null) {
index = terms.size();
terms.add(term);
map.put(term, index);
}
return index;
}
@Override
public void output(DataOutputStream out) throws IOException {
out.writeInt(terms.size());
for (Term term : terms) {
term.output(out);
}
}
}
和Term
都会实现NonDuplicateList
接口输出。
为了保持Outputable
线程安全,我使用NonDuplicateList
来保护方法synchronized
,并且当前调用addTerm(Term)
时性能与预期一样糟糕。
addTerm
似乎不适合这种情况,因为它不能保持强大的数据一致性。知道如何在不失去线程安全性的情况下提高ConcurrentHashMap
的性能吗?
编辑:
addTerm
方法,即通过output
的迭代,可能不是线程安全的,因为在同时调用NonDuplicateList
后只有一个线程会访问此方法,但addTerm
必须返回一旦将术语添加到addTerm
中,就立即将索引值。
答案 0 :(得分:0)
如果您可以牺牲ConcurrentHashMap
返回类型,则有可能在您的实现中重用addTerm
。您可以返回boolean
而不是返回实际索引,这表示添加是成功还是生成重复。这还允许您删除方法同步并提高性能:
private ConcurrentMap<Term, Boolean> map;
private List<Term> terms;
public boolean addTerm(Term term) {
Boolean previousValue = map.putIfAbsent(term, Boolean.TRUE);
if (previousValue == null) {
terms.add(term);
return true;
}
return false;
}
答案 1 :(得分:0)
恐怕你不会在这里得到更快的解决方案。关键是在不需要时避免同步。如果你不介意弱一致性,使用ConcurrentHashMap
迭代器可能比在创建迭代器时迭代或获取一致快照时阻止其他线程添加项目要便宜得多。
另一方面,当您需要同步和一致的迭代器时,您需要ConcurrentHashMap
的替代方法。我想到的是java.util.Collections#synchronizedMap
,但它在对象级别使用同步,因此每次读/写操作都需要获取锁,这是性能开销。
查看ConcurrentSkipListMap
,它可以保证各种操作的平均O(log(n))
性能。它还有许多ConcurrentHashMap没有的操作:ceilingEntry/Key
,floorEntry/Key
等。它还维护一个排序顺序,如果你使用它,否则必须计算(费用显着) ConcurrentHashMap。也许有可能摆脱list + map并使用ConcurrentSkipListMap
代替。可以使用ConcurrentSkipListMap
api计算元素索引。