以线程安全方式发布非线程安全对象字段

Lou*_*uis 7 java concurrency composition thread-safety mutability

我遇到了Java并发问题.是的,我看了几乎完全相同标题的问题,但他们似乎都在寻求微妙的不同之处.是的,我已经阅读了Java Concurrency in Practice.是的,我能看到为什么它是事实上的对话题参考.是的,我已经阅读了专门针对线程安全类中的发布字段的部分.是的,我仍然会问一个关于Java的并发问题,不管我知道有人会简单地指出我那本书.

这让我很难过 - 我知道你可以通过确保具有易变性和/或同步访问的正确读/写命令,以线程安全的方式轻松发布可变原语字段,并且64位原语需要具有原子访问权限由于其读/写操作缺乏原子性.我知道在需要在类的字段的特定"快照"上执行的代码块上使用锁.我完全了解原子包和AtomicLong <>等好东西.

但是我仍然对将非线程安全对象作为线程安全类中的字段发布感到困惑.

从我所看到的,一旦你在getter中返回对它的引用,你就可以在任何时候对调用者提供前所未有的对象内容访问权限.此外,如果你给一个setter,你允许他们将对象引用设置为一个对象,它们可以在他们使用setter的对象之外控制它们.

无论如何,我无法解决从非线程安全对象组成线程安全类而不使它们全部私有/受保护并在类中为所有非线程安全对象创建所有非线程安全对象的线程安全包装器方法让该类的用户可能想要使用.这听起来像是一个样板噩梦.

我的意思是,如果你将一个AtomicReference <>返回给getter中的对象,他们可以使用.get()来再次获得对它的非同步访问.

我考虑的另一种方法是让所有getter基于旧的获取非线程安全对象的新副本,这意味着修改将是无关紧要的,同样适用于setter.但是Java有一个无可救药的复杂系统来克隆对象(浅拷贝与深拷贝与特定拷贝等),这有点让我无法做到这一点.而且,这是如此低效,以至于它不会比使用像Clojure那样为不变性而设计的语言更快.事实上,考虑到这些语言允许多条不可变数据在幕后共享相同的数据,它可能会慢得多.

那么,如何以可行的方式编写已发布的非线程安全对象的线程安全类?

提前致谢.

ya_*_*ser 4

如果对不安全对象的引用已逃逸到周围线程 - 您无法采取任何措施来阻止其他线程改变状态,因此您应该保持引用的安全。如果您需要返回复杂的对象,请将数据设为私有,引入封装访问和修改的方法,并制作线程安全的副本(是的,克隆很麻烦)。

尝试查看http://en.wikipedia.org/wiki/Law_of_Demeter设计原理。quote:特别是,一个对象应该避免调用另一个方法返回的成员对象的方法。对于许多使用点作为字段标识符的现代面向对象语言,该法则可以简单地表述为“仅使用一个点”。也就是说,代码 abMethod() 违反了 a.Method() 不违反的法律。举个简单的例子,当一个人想遛狗时,命令狗的腿直接走是愚蠢的;相反,人们命令狗并让它照顾自己的腿。

ps:恐怕这是一个开放式问题。