2013-04-26 87 views
0

对象存储在线程安全集合(如CopyOnWriteArrayList)线程安全吗?让我们说存储的对象是可变的(不是线程安全的),那么集合(这里是CopyOnWriteArrayList)是线程安全的事实提供了对存储在其中的引用的线程安全性的任何保证?存储在线程安全集合线程中的对象是否安全?

+0

对不起,你在问什么?你是在谈论由集合支持的数组中的引用变量,还是集合中的实际对象? – gparyani 2013-04-26 02:27:31

+0

对不起,我不清楚我的问题。我指的是集合中的对象。 – GJ13 2013-04-26 02:29:38

回答

5

不,对象不是线程安全的;如果两个线程更改从CopyOnWriteArrayList检索到的可变对象,则它们将导致数据竞争。

如果一个集合是线程安全的,那么这意味着两个线程可以添加/删除集合中的对象而不会破坏集合(例如,ArrayList不是线程安全的,所以如果两个线程每个尝试添加一个对象那么一个或两个对象可能会丢失),但是集合中的对象仍然需要同步以使它们成为线程安全的。

+0

是的,但太多的同步可能会导致程序运行速度变慢(或在某些情况下,死锁)。 – gparyani 2013-04-26 02:32:31

+1

是的,这就是为什么Java为了让“程序员决定什么要同步”的方法而使用像'ArrayList'或'StringWriter这样的类从类似'Vector'或'Stringbuffer'的类中移出“总是同步一切” ' – 2013-04-26 02:34:11

+2

@gparyani - “太多”同步不会导致死锁。死锁是由*不正确的同步模式引起的。这种模式不是数量上的差异。 – 2013-04-26 02:41:39

2

有一些保证,通常线程安全存储类似于记忆效应的易失变量。

volatile Foo var;    final Vector<Foo> vars = new Vector<>() 

// thread 1     // thread 1 
foo.bar = bar; [1]   foo.bar = bar;   [1] 
var = foo;      vars.set(0, foo); 

// thread 2     // thread 2 
bar = foo.bar; [2]   bar = vars.get(0).bar; [2] 

//read[2] sees write[1]  // read[2] sees write[1] 

基本上,插入之前的写入操作在读取后应该是可见的。

1

唯一提供的线程安全保证是对象将被“安全地发布”。也就是说,它们将对所有线程立即可见(这包括对对象及其内部状态的引用)。

示例:如果线程A写入X,并且线程B读取,则B保证将X视为A离开它。换句话说,读取和写入操作与它们发生的顺序一致。

还有其他的方法来完成这样使用final,或volatile,或AtomicReference,或锁同样的事情(这是线程安全的集合做),或静态初始化。有关详细信息,请参阅“实践中的Java并发”一书。