【发布时间】:2014-06-25 15:43:50
【问题描述】:
我有一个案例,我想避免防御性副本,因为数据可能会被修改,但通常只是读取,而不是写入。所以,我想使用不可变对象和函数式mutator方法,这很常见(java lombok 能够或多或少地自动完成)。我进行的方式如下:
public class Person {
private String name, surname;
public Person(String name, String surname) {....}
// getters...
// and instead of setters
public Person withName(String name) {
Person p= copy(); // create a copy of this...
p.name= name;
return p;
}
public Person copy() {....}
}
所以,如果要获取另一个名字的人的副本,我会打电话给
p= new Person("Bar", "Alfred");
...
p= p.withName("Foo");
实际上,对象相当大(我最终使用序列化来避免编写复制代码的负担)。
现在,在浏览网页时,我发现此实现存在潜在的并发问题,因为我的字段不是最终的,因此,并发访问可能会看到返回的副本,例如,没有更改新名称(因为有在这种情况下,对操作顺序没有保证)。
当然,在当前的实现中,我不能使我的字段成为最终的,因为我先做一个副本,然后更改副本中的数据。
所以,我正在为这个问题寻找一个好的解决方案。
我可能会使用 volatile,但我觉得这不是一个好的解决方案。
另一种解决方案是使用构建器模式:
class PersonBuilder {
String name, surname; ....
}
public class Person {
private final String name, surname;
public Person(PersonBuilder builder) {...}
private PersonBuilder getBuilder() {
return new PersonBuilder(name, surname);
}
public Person withName(String name) {
PersonBuilder b= getBuilder();
b.setName(name);
return new Person(b);
}
}
这里有什么问题吗,最重要的是,有没有更优雅的方式来做同样的事情?
【问题讨论】:
-
如果你的类是不可变的,那么根据定义它不能有修饰符。但是一个相当有趣的问题......
-
我所做的是只有一个线程本地的可变数据。这避免了复制大型对象的需要,并且可能会使用具有大型不可变对象的多个线程来执行。
-
你想如何管理你的“而不是带有XX函数的setter”,每个属性一个只针对某些属性?
-
实际上对于大多数属性。
标签: java multithreading immutability final volatile