以线程安全方式发布非线程安全对象字段 [英] Publishing Non-Thread Safe Object Fields in a Thread-Safe Manner

查看:139
本文介绍了以线程安全方式发布非线程安全对象字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Java并发问题。是的,我看了几乎完全相同的题目的问题,但他们似乎都在问不同的东西。是,我已阅读实践中的Java并发。是的,我可以看到为什么是主题的 defacto 参考。是的,我已经阅读了有关在线程安全类中发布字段的部分。是的,我仍然会问Java上的一个并发问题,不管我知道有人会简单地指向这本书。

I've got a problem with Java concurrency. Yes, I looked at questions with almost the exact same title, but they all seemed to be asking subtly different things. Yes, I've read Java Concurrency in Practice. Yes, I can see why it's the defacto reference for the topic. Yes, I've read the section specifically on publishing fields in thread-safe classes. Yes, I'm still going to ask a concurrency question on Java regardless of the fact that I know someone will simply point me to that book.

这让我很累 - 我知道你可以通过确保正确的读/写顺序与易失性和/或同步访问以线程安全的方式轻松发布可变的原始字段,并且64位原语需要原子访问,由于缺乏在其读/写操作中的原子性。我知道在需要在类的字段的特定快照上执行的代码块上使用锁。我完全知道原子包,像AtomicLong>等的好东西。

This has me stumped though -- I know that you can easily publish mutable primitive fields in a thread-safe manner by ensuring correct read/write orders with volatility and/or synchronized access, and that the 64-bit primitives needs to have atomic access due to the lack of atomicity in its read/write operations. I know about using locks on chunks of code that need to execute on a specific 'snapshot' of the class's fields. I'm fully aware of the atomic package with goodies like AtomicLong<>, etc.

但是我仍然困惑关于发布非线程安全的对象字段在线程安全类中。

But I'm still confused with regards to publishing non-thread-safe objects as fields in a thread-safe class.

从我可以看到,只要你在getter中返回对它的引用,你给了前所未有的访问对象的内容给调用者,他们可以在任何时候使用。此外,如果你给一个setter,你允许他们设置对象引用对象,他们可以控制在他们使用setter的对象之外。

From what I can see, as soon as you return the reference to it in the getter, you've given unprecedented access to the object's contents to the caller which they can use at any point. Also, if you give a setter, you're allowing them to set the object reference to an object they can potentially control outside the object they're using the setter for.

我无法从非线程安全的对象编写线程安全类,而不使它们全部私有/保护,并在类中创建线程安全包装器方法全部方法所有非线程安全对象都有类的用户可能想使用。

I can't work out anyway of composing a thread-safe class out of non-thread-safe objects without making them all private/protected and creating thread-safe wrapper methods in the class for all the methods all the non-thread safe objects have that the user of the class may want to use. And this just sounds like a boilerplate nightmare.

我的意思是,如果你在一个getter中返回一个AtomicReference<>给对象,他们只需要使用.get

I mean, if you return an AtomicReference<> to the object in a getter, they can just use .get() to get non-synchronized access to it again.

我考虑的另一种方法是让所有getter返回基于旧线程的非线程安全对象的新副本,意味着修改将是不相关的,同样适用于setter。但Java有一个绝对复杂的系统克隆对象(浅拷贝vs深拷贝vs特定拷贝等),这有点让我不屑。此外,这是非常低效的,它不会比使用为设计像Clojure不变性的语言更快。事实上,考虑到这样的语言允许多个不可变数据在后台共享相同的数据,它可能会慢得多。

Another way I considered was to have all the getters return new copies of the non-thread-safe object based on the old one, meaning that modifications would be irrelevant, with the same applying to setters. But Java has a hopelessly complicated system for cloning objects (shallow-copy vs deep-copy vs specific-copying etc), which kinda puts me off doing that. Also, this is so inefficient that it wouldn't be any faster than using a language that's designed for immutability like Clojure. In fact, it would probably be far slower given that such languages allow multiple pieces of immutable data to share the same data behind the scenes.

所以,我如何编写线程发布非线程安全对象的安全类是否可行?

So, how do I compose thread safe classes of published non-thread safe objects in a viable manner?

提前感谢。

推荐答案

如果对不安全对象的引用已经转移到了周围的线程 - 你不能做任何事情停止其他线程来改变状态,所以你应该保持引用安全。如果你需要返回复杂的对象,使数据为私有,抛出封装访问和修改的方法,并使线程安全的副本(是的,克隆是繁琐的)。

If reference to unsafe objects has escaped to surrounding threads - you can not do anything to stop other threads to mutate the state, so you should keep the references safe. Make the data private, throw in methods that encapsulate access and modification and make thread-safe copies (yes, cloning is cumbersome) if you ever need to return complex objects.

尝试查看 http://en.wikipedia.org/wiki/Law_of_Demeter 设计原则。
quote:特别是,一个对象应该避免调用另一个方法返回的成员对象的方法。对于许多使用点作为字段标识符的现代面向对象语言,法则可以简单地表示为只使用一个点。也就是说,代码a.b.Method()打破了法律,其中a.Method()没有。作为一个简单的例子,当一个人想走狗时,命令狗的腿直接走路是愚蠢的;而是一个命令狗,让它照顾自己的腿。

Try to look at http://en.wikipedia.org/wiki/Law_of_Demeter design principle. quote: In particular, an object should avoid invoking methods of a member object returned by another method. For many modern object oriented languages that use a dot as field identifier, the law can be stated simply as "use only one dot". That is, the code a.b.Method() breaks the law where a.Method() does not. As a simple example, when one wants to walk a dog, it would be folly to command the dog's legs to walk directly; instead one commands the dog and lets it take care of its own legs.

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

ps: I'm afraid it is open-ended question.

这篇关于以线程安全方式发布非线程安全对象字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆