线程中的线程安全对象字段
我遇到了Java并发的问题。 是的,我用几乎完全相同的标题来看问题,但他们似乎都在提出细微差别的问题。 是的,我已阅读Java Concurrency in Practice。 是的,我可以看到为什么它是该主题的事实参考。 是的,我已经阅读了关于线程安全类中发布字段的专门章节。 是的,我仍然会问一个关于Java的并发问题,而不管我知道有人会直接指向那本书。
这让我难以忍受 - 我知道,通过确保正确的读/写顺序具有波动性和/或同步访问,并且64位基元需要原子访问,您可以以线程安全的方式轻松发布可变原始字段由于其读/写操作缺乏原子性。 我知道如何在需要在类的字段的特定“快照”上执行的代码块上使用锁。 我充分意识到像AtomicLong <>等好东西的原子包。
但是我仍然对在线程安全类中将非线程安全的对象发布为字段感到困惑。
从我所看到的情况来看,只要你在getter中返回引用,你就可以以前所未有的方式访问对象的内容给调用者,他们可以随时使用它。 另外,如果你给了一个setter,你可以让它们将对象引用设置为一个对象,它们可以在它们使用setter的对象之外进行控制。
无论如何,我无法从非线程安全的对象中构建一个线程安全的类,而不将它们全部设置为private / protected,并在类中为所有方法创建线程安全的wrapper方法,所有非线程安全的对象有类的用户可能想要使用。 这听起来就像是一个拙劣的恶梦。
我的意思是,如果您将AtomicReference <>返回给getter中的对象,则可以使用.get()再次获得非同步访问。
我考虑的另一种方式是让所有的getter都返回基于旧线程的非线程安全对象的新副本,这意味着这些修改将无关紧要,同样适用于setters。 但是Java有一个克隆对象的复杂系统(浅拷贝vs深拷贝vs特定拷贝等),这让我不能这么做。 而且,这样做效率低下,因此不会比使用像Clojure这样的不可变性的语言更快。 事实上,如果这种语言允许多块不可变数据在幕后共享相同的数据,它可能会慢得多。
那么,如何以可行的方式编写已发布的非线程安全对象的线程安全类?
提前致谢。
如果引用不安全的对象已经转移到周围的线程 - 你不能做任何事情来阻止其他线程改变状态,所以你应该保持引用的安全。 如果您需要返回复杂的对象,请将数据设置为私有,并引入封装访问和修改的方法,并创建线程安全的副本(是的,克隆是繁琐的)。
试着看看http://en.wikipedia.org/wiki/Law_of_Demeter的设计原则。 quote:特别是,一个对象应该避免调用另一个方法返回的成员对象的方法。 对于许多使用点作为字段标识符的现代面向对象语言,该法则可以简单地表述为“仅使用一个点”。 也就是说,代码abMethod()违反了a.Method()不适用的法则。 举一个简单的例子,当一个人想要走路时,指挥狗的腿直接走路是愚蠢的; 而是一个命令狗,让它照顾自己的腿。
ps:恐怕这是开放式的问题。
链接地址: http://www.djcxy.com/p/53733.html