2010-10-19 178 views
0

在下面的代码片段中,为什么需要返回数据[i]的副本。如果不进行复制,多线程环境中究竟发生了什么。Java:返回对象的副本

protected Object[] data; 
.. 
public synchronized Object get(int i) 
throws NoSuchElementException 
{ if (i < 0 || i >= size) 
     throw new NoSuchElementException(); 
    return data[i]; 
} 

回答

4

为什么它希望返回数据[I]的副本。

你在指数i返回参考副本,而不是一个对象的副本。

除非通过例如data[i].clone()创建对象的副本,否则您将始终拥有一个对象并在线程中共享对它的引用。在多个线程中共享对单个对象的引用没有任何问题。

如果没有进行复制,多线程环境中究竟发生了什么。

好吧,除非你使用的同步方法同步线程,等待/通知或java.util.concurrent - 班你可能最终与race-conditions。竞争条件基本上是执行结果依赖于特定调度(线程可以执行的顺序)的情况。

如果您在线程中共享某个类的对象,则应将其设计为"thread safe"。如果您的对象代表value object,我建议您将它制作为immutable

+0

为什么需要它? – devnull 2010-10-19 06:36:06

+2

@iJeeves如果你不需要它,它是不需要的。看到我的答案。 – 2010-10-19 06:37:19

2

嗯,我没有看到这个方法没有错,因为它是 - 它没有复制。这取决于你打算如何处理返回的对象。如果您将从不同的线程修改它,那么为每个线程返回一个副本是一个好主意。

1

由于该方法是同步的,并且除非同一个包中的其他人不处理数据数组,否则应该没有多线程问题。

1

因为它可能更舒适的调用代码。如果你没有返回一个副本(如你的例子所示),如果你想避免竞争条件,你必须在返回的引用(data [i])上同步。

1

希望返回[I]

因为你的get()是同步的,很可能多个线程访问将并行数据对象的副本。现在,这将导致问题,如果以下几点为真

  • 存储在数组中的对象是muteable(可改变状态)
  • 对象的方法不同步(该对象不是线程)

如果这些是真的,如果两个线程同时处理对象,最终可能会导致对象处于无效状态。创建对象的副本可以防止这种情况发生,因为每个线程都会处理它自己的副本。

0

由于多个线程可以直接访问同一个对象,因此您可能会遇到意外行为的问题。

考虑以下几点:

线程A:

Object foo = get(1); 
foo.member += 5; 

线程B:

Object bar = get(1); 
bar.member = 2; 

假设这2个线程同时运行时,你无法知道什么样的最终状态的方式存储在数据[1]中的对象将是。线程切换控制点是不可预测的,虽然99%的时间可以正常工作,但您的代码可能会出现间歇性错误。

你真正想要做的是保护任何修改对象数据[]与“同步”关键词的状态的方法。吸气剂,吸附剂等应全部同步。有一个同步的方法,只是实现对象的引用是毫无意义的。

0

请不要使用克隆来创建副本,它有它自己的错误。使用复制构造函数或创建一个新对象并设置成员值并返回相同的值。