静态初始化的 unmodifyingCollection.get 保证不可变吗?

发布于 2024-08-18 13:03:58 字数 271 浏览 3 评论 0 原文

静态初始化的 unmodifyingCollection.get 保证不可变吗?

对于:

静态最终映射 FOO = Collections.unmodifyingMap(new HashMap());

多个线程使用 get 方法是否可以避免出现问题?

即使 FOO 中的项目无法添加/删除,是什么阻止 get 方法出于缓存目的而操纵 FOO 的内部状态等。如果以任何方式修改内部状态,则不能同时使用 FOO。如果是这样的话,java中真正的不可变集合在哪里呢?

Is static initialized unmodifiableCollection.get guaranteed immutable?

For:

static final Map FOO =
Collections.unmodifiableMap(new HashMap());

Can multiple threads use method get and not run into problems?

Even through items in FOO cannot be added/removed, what's stopping the get method from manipulating FOO's internal state for caching purposes, etc. If the internal state is modified in any way then FOO can't be used concurrently. If this is the case, where are the true immutable collections in java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

妥活 2024-08-25 13:03:58

给出具体的例子:

static final Map FOO = Collections.unmodifiableMap(new HashMap());

那么 FOO 将是不可变的。它也永远不会有任何元素。考虑到更一般的情况:

static final Map BAR = Collections.unmodifiableMap(getMap());

那么这是否是不可变的完全取决于其他人是否可以访问底层 Map,以及它是什么类型的 Map。例如,如果它是 LinkedHashMap,则底层链表可以通过访问顺序进行修改,并且可以通过调用 get() 进行更改。最安全的方法(使用非并发类)是:

static final Map BAR = Collections.unmodifiableMap(new HashMap(getMap()));

HashMap 的 javadocs 意味着只要您不对映射进行结构更改,那么同时使用它就是安全的,因此这对于您可以使用的任何访问器来说都是安全的使用,即获取各种集合并迭代它们,然后 get() 应该是安全的。

如果您可以使用并发类,那么您也可以这样做:

static final Map BAR = Collections.unmodifiableMap(new ConcurrentHashMap(getMap());

这对于多线程使用来说是显式安全的,因为 ConcurrentHashMap 是显式多线程访问安全的。内部状态可能是可变的,但外部可见状态不会,并且由于该类保证是线程安全的,因此我们可以安全地认为它是外部不可变的。

Given the specific example:

static final Map FOO = Collections.unmodifiableMap(new HashMap());

Then FOO will be immutable. It will also never have any elements. Given the more general case of:

static final Map BAR = Collections.unmodifiableMap(getMap());

Then whether or not this is immutable is entirely dependent on whether or not someone else can get to the underlying Map, and what type of Map it is. For example, if it is a LinkedHashMap then the underlying linked list could be modified by access order, and could change by calling get(). The safest way (using non-concurrent classes) to do this would be:

static final Map BAR = Collections.unmodifiableMap(new HashMap(getMap()));

The javadocs for HashMap imply that so long as you make no structural changes to the map, then it is safe to use it concurrently, so this should be safe for any of the accessors that you can use, that is getting the various sets and iterating over them and get() should then be safe.

If you can use the concurrent classes, then you could also do:

static final Map BAR = Collections.unmodifiableMap(new ConcurrentHashMap(getMap());

This will be explicitly safe to use from multiple threads, since ConcurrentHashMap is explicitly multi-thread access safe. The internal state might be mutable, but the externally visible state will not be, and since the class is guaranteed to be threadsafe, we can safely consider it to be externally immutable.

怪我闹别瞎闹 2024-08-25 13:03:58

冒着听起来像是我在疯狂做广告的风险,请使用 Google 不可变集合 并完成它。

At the risk of sounding like I'm on an advertising spree, use the Google Immutable Collections and be done with it.

难如初 2024-08-25 13:03:58

其实是个好问题。想想 WeakHashMap - 它可以在不调用突变操作的情况下进行更改。访问顺序模式下的 LinkedHashMap 大致相同。

HashMap 状态的 API 文档:

请注意,此实现不是
同步。
如果是多个线程
同时访问哈希图,并且在
至少有一个线程修改
从结构上看,它必须是
外部同步。 (结构
修改是任何操作
添加或删除一个或多个映射;
只是改变相关的值
带有一个实例已经存在的密钥
包含不是结构性的
修改。)

大概这应该是当且仅当。这意味着如果 HashMap 是“有效不可变”,则 get 不需要同步。

Actually a good question. Think WeakHashMap - that can change without having a mutation operation called on it. LinkedHashMap in access-order mode is much the same.

The API docs for HashMap state:

Note that this implementation is not
synchronized.
If multiple threads
access a hash map concurrently, and at
least one of the threads modifies the
map structurally, it must be
synchronized externally. (A structural
modification is any operation that
adds or deletes one or more mappings;
merely changing the value associated
with a key that an instance already
contains is not a structural
modification.)

Presumably that should be if and only if. That means that get does not need to be synchronised if the HashMap is 'effectively immutable'.

金兰素衣 2024-08-25 13:03:58

Java SDK 中不存在真正的不可变映射。克里斯建议的所有地图都只是线程安全的。不可修改的 Map 也不是不可变的,因为如果底层 Map 发生更改,也会出现 ConcurrentModificationException 。

如果您想要真正不可变的映射,请使用 Google Collections / Guava 中的 ImmutableMap。

There is no true immutable map in Java SDK. All of the suggested Maps by Chris are only thread safe. The unmodifiable Map is not immutable either since if the underlying Map changed there will ConcurrentModificationException as well.

If you want the truly immutable map, use ImmutableMap from Google Collections / Guava.

娇俏 2024-08-25 13:03:58

我建议任何线程操作使用 ConcurrentHashMap 或 HashTable,两者都是线程安全的。

I would suggest for any threaded operation to use ConcurrentHashMap or HashTable, both are thread-safe.

居里长安 2024-08-25 13:03:58

返回的映射上的 getter 是否碰巧与某些内部状态发生冲突并不重要,只要对象遵守其契约(即成为无法修改的映射)。所以你的问题是“找错树”。

如果您没有对其所包装的地图的所有权和控制权,那么您对 ​​UnmodifyingMap 保持谨慎是正确的。例如

Map<String,String> wrapped = new HashMap<String,String>();
wrapped.add("pig","oink");
Map<String,String> wrapper = Collections.unmodifiableMap(wrapped);
System.out.println(wrapper.size());
wrapper.put("cow", "moo"); // throws exception
wrapped.put("cow", "moo");
System.out.println(wrapper.size()); // d'oh!

Whether a getter on the returned map happens to twiddle with some internal state is unimportant, as long as the object honors its contract (which is to be a map that cannot be modified). So your question is "barking up the wrong tree".

You are right to be cautious of UnmodifiableMap, in the case where you do not have ownership and control over the map it wraps. For example

Map<String,String> wrapped = new HashMap<String,String>();
wrapped.add("pig","oink");
Map<String,String> wrapper = Collections.unmodifiableMap(wrapped);
System.out.println(wrapper.size());
wrapper.put("cow", "moo"); // throws exception
wrapped.put("cow", "moo");
System.out.println(wrapper.size()); // d'oh!
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文