对于我工作的项目中的JPA-Entities,List或Map类型的属性总是初始化为同步实现Vector和Hashtable。
(Unsynchronized ArrayList和HashMap是Java中的标准实现,除非真的需要同步。)
有谁知道为什么需要同步收藏?我们使用EclipseLink。
当我问起这件事时,没有人知道为什么这样做。它似乎总是像这样完成。也许旧版EclipseLink需要这个?
我问了两个原因:
示例实体:
@Entity
public class Person {
...
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable( ... )
private List<Role> accessRoles;
@ElementCollection
@CollectionTable( ... )
@MapKeyColumn(name="KEY")
@Column(name="VALUE")
private Map<String, String> attrs;
public Person() {
// Why Vector/Hashtable instead of ArrayList/HashMap?
accessRoles = new Vector<Role>();
attrs = new Hashtable<String, String>();
}
public List<Role> getAccessRoles() {
return accessRoles;
}
public void setAccessRoles(List<Role> accessRoles) {
this.accessRoles = accessRoles;
}
public Map<String, String> getAttrs() {
return attrs;
}
public void setAttrs(Map<String, String> attrs) {
this.attrs = attrs;
}
}
答案 0 :(得分:5)
通常不需要Vector和更常用的ArrayList。因此,如果您当前的代码库中充满了向量,这有点代码味道,确保您的团队成员知道差异是明智的。另请参阅What are the differences between ArrayList and Vector?和Why is Java Vector class considered obsolete or deprecated?
这并不意味着你应该进行大清理并用ArrayLists替换现有代码中的所有向量。
因此,除非您目前遇到性能问题,或者明确(重新)设计整个代码库的同步,否则您可能会冒险修复并发错误而没有任何好处。
另外,请注意,当多个线程同时访问您的集合时,性能会受到使用向量的影响最大。因此,如果 因性能损失而决定替换Vector,那么您需要非常小心地保持访问充分同步。
编辑:你特别询问EclipseLink JPA。
如果他们要求你使用Vectors和Hashtables,那将是相当令人惊讶的,因为这意味着他们会要求你依赖过时的数据结构。 在their examples中,他们使用ArrayLists和HashMaps,因此我们可以得出结论,确实不是这样。
在源代码中更具体地潜水,我们可以看到他们的CollectionContainerPolicy使用了Collection接口而不关心集合的实现。但确实,令人惊讶的是,当你的内部集合类是Vector时,会有特殊情况。例如,请参阅buildContainerFromVector。它的default container class是Vector,虽然你可以改变它。
另见the documentation for the Container policy。
EclipseLink和你的列表遇到的最具侵入性的时刻是你懒得加载集合。 EclipseLink将使用自己的IndirectList替换集合,该集合在内部使用Vector。请参阅What collections does jpa return?因此,在这些情况下,EclipseLink将始终为您提供Vector(!),它甚至不会影响您在集合初始化中指定的集合。
所以EclipseLink确实偏爱使用Vectors和使用 使用EclipseLink的向量意味着减少对象引用的复制 一个集合到另一个。
答案 1 :(得分:1)
EclipseLink的许多内部可以追溯到Vector和Hashtable是Java中的标准集合类型的时代。 EclipseLink当时是TopLink,它起源于Smalltalk的持久性框架 - 因此,很多EclipseLinks代码实际上比Java本身更早,可以这么说。 多年来,我一直使用TopLink,并且始终使用Vector和Hashtable对集合属性进行标准映射。 对我而言,仍然出现在EclipseLink中的Vector和Hashtable的唯一合理解释是,它已经在这样的工作很长一段时间了 - 因为它正在工作 - 迄今为止没有人能够改变它。
对于我自己,我再也不会使用Vector或Hashtable了。如果我需要同步集合,我宁愿使用SynchronizedList ... Map等API。 只是我的2克拉。
答案 2 :(得分:1)
通过eclipselink的代码库,看起来vector的用法是从较旧的代码库继承的,并且很像Vector类本身 - 遗留。 不知何故,意图是使用Vector允许多个线程在懒惰加载的关系上安全地行动 - &#34;间接&#34;用eclipselink的说法。 (更多关于概念here - 讨论的不同类型的间接是ValueHolder间接,透明间接,代理间接等。) 但是,在通常的用例中,通常不会在多个线程之间共享实体及其关系。每个线程都获得它自己的实体副本及其副本 如果在他们自己的工作单元中访问这些关系。
在ValueHoder间接的情况下 - ValueHoderInterface的一个实现是ValueHoder,它通常用向量初始化。代码的相关部分如下所示 代码注释。评论也很有趣
IndirectList.java
..........................
.........................
/**
* INTERNAL:
* Return the valueHolder.
* This method used to be synchronized, which caused deadlock.
*/
public ValueHolderInterface getValueHolder() {
// PERF: lazy initialize value holder and vector as are normally set after creation.
if (valueHolder == null) {
synchronized(this) {
if (valueHolder == null) {
valueHolder = new ValueHolder(new Vector(this.initialCapacity, this.capacityIncrement));
}
}
}
return valueHolder;
}
...................
..................
答案 3 :(得分:0)
你不需要JPA的同步集合,它应该只与业务逻辑有关..我认为不需要这个..因为你会知道。
所以基本上建议使用不同步,它会提高性能。
答案 4 :(得分:0)
由于@flup回答了一些有趣的参考资料,我只能做出一些额外的假设: