如何在 Java 中返回线程安全/不可变集合?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6658682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:50:03  来源:igfitidea点击:

How to return a thread safe/immutable Collection in Java?

javalistthread-safetysynchronizedunmodifiable

提问by zw324

In the project I am coding, I need to return a thread safe and immutable view from a function. However, I am unsure of this. Since synchronizedListand unmodifiableListjust return views of a list, I don't know if

在我正在编码的项目中,我需要从函数返回一个线程安全且不可变的视图。但是,我不确定这一点。由于synchronizedList并且unmodifiableList只是返回列表的视图,我不知道是否

Collections.synchronizedList(Collections.unmodifiableList(this.data));

Collections.synchronizedList(Collections.unmodifiableList(this.data));

would do the trick.

会做的伎俩。

Could anyone tell me if this is correct, and in case it is not, are there any situations that this would likely to fail?

谁能告诉我这是否正确,如果不正确,是否有任何情况可能会失败?

Thanks for any inputs!

感谢您的任何投入!

回答by Ray

I find this to be a real gap in the JDK. Fortunately, a team over a Google, led by Java Collections designer Joshua Bloch, have created a librarythat includes truly immutable collections.

我发现这是 JDK 中的一个真正差距。幸运的是,由 Java Collections 设计师Joshua Bloch领导的 Google 团队创建了一个包含真正不可变集合的

ImmutableListin particular is the implementation you're looking for. Hereis a quick sketch of some of the features of Guava's ImmutableCollections.

ImmutableList特别是您正在寻找的实现。是 Guava 的 ImmutableCollections 的一些特性的简要概述。

回答by duffymo

I think unmodifiable is sufficient. You can't write to it, which is what causes problems for multi-threaded access. It's read-only, so the additional step of synchronizing seems unnecessary to me.

我认为不可修改就足够了。您无法写入它,这就是导致多线程访问出现问题的原因。它是只读的,因此同步的额外步骤对我来说似乎没有必要。

Best to check out the source code when there are questions like this. Looks like it returns an UnmodifiableList:

当有这样的问题时,最好查看源代码。看起来它返回一个UnmodifiableList

/**
 * @serial include
 */
static class UnmodifiableList<E> extends UnmodifiableCollection<E>
                  implements List<E> {
    static final long serialVersionUID = -283967356065247728L;
final List<? extends E> list;

UnmodifiableList(List<? extends E> list) {
    super(list);
    this.list = list;
}

public boolean equals(Object o) {return o == this || list.equals(o);}
public int hashCode()       {return list.hashCode();}

public E get(int index) {return list.get(index);}
public E set(int index, E element) {
    throw new UnsupportedOperationException();
    }
public void add(int index, E element) {
    throw new UnsupportedOperationException();
    }
public E remove(int index) {
    throw new UnsupportedOperationException();
    }
public int indexOf(Object o)            {return list.indexOf(o);}
public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
public boolean addAll(int index, Collection<? extends E> c) {
    throw new UnsupportedOperationException();
    }
public ListIterator<E> listIterator()   {return listIterator(0);}

public ListIterator<E> listIterator(final int index) {
    return new ListIterator<E>() {
    ListIterator<? extends E> i = list.listIterator(index);

    public boolean hasNext()     {return i.hasNext();}
    public E next()          {return i.next();}
    public boolean hasPrevious() {return i.hasPrevious();}
    public E previous()      {return i.previous();}
    public int nextIndex()       {return i.nextIndex();}
    public int previousIndex()   {return i.previousIndex();}

    public void remove() {
        throw new UnsupportedOperationException();
            }
    public void set(E e) {
        throw new UnsupportedOperationException();
            }
    public void add(E e) {
        throw new UnsupportedOperationException();
            }
    };
}

回答by Awan Biru

Collections.unmodifiableList(this.data) 

Will do, as it will return a view. Any modification attempts on this view will result of UnsupportedOperationExceptionbeing thrown. Below are excerpt of Collections#unmodifiableListdocumentation.

会做,因为它会返回一个视图。对该视图的任何修改尝试都将UnsupportedOperationException被抛出。以下是Collections#unmodifiableList文档的摘录。

Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.

......

返回指定列表的不可修改视图。这种方法允许模块为用户提供对内部列表的“只读”访问。对返回列表的查询操作“通读”到指定列表,并尝试修改返回的列表,无论是直接还是通过其迭代器,都会导致 UnsupportedOperationException。

......

java 8 java.util.Collections javadoc

java 8 java.util.Collections javadoc

回答by Basil Bourque

copyOf

copyOf

Yes, now built into Java 10 and later.

是的,现在内置于 Java 10 及更高版本中。

Each of these returns a separate collection of the objects found in the original. The returned collection is nota view onto the original, as is the case with the Collections.unmodifiable…utility class methods.

这些中的每一个都返回在原始对象中找到的对象的单独集合。返回的集合不是原始集合的视图,就像Collections.unmodifiable…实用程序类方法的情况一样。

回答by Rob Moffat

These views won't return you truly thread-safe collections. There is always the possibility that someone will modify either the backing collection, or the elements within the collection.

这些视图不会返回真正线程安全的集合。总是有可能有人会修改支持集合或集合中的元素。

To solve this, you need to use immutable collections and immutable elements. Then, thread-safety happens as a result.

要解决这个问题,您需要使用不可变集合和不可变元素。然后,线程安全就会发生。

Clojure contains such immutable (or persistent) collections.

Clojure 包含此类不可变(或持久)集合

Put simply, adding or removing new elements returns a new collection, which in general doesreuse large parts of the old collection through clever use of Trie-type data structures.

简单地说,添加或移除新的元素返回一个新的集合,其通常重用通过巧妙地利用Trie树型数据结构的收旧的大部分地区。

On their own, these are a poor fit for using in straight Java.

就其本身而言,这些不适合在纯 Java 中使用。

Pure4jis an attempt to port these (and the immutable/value based style advocated by Clojure) to the Java language. It might be what you're after.

Pure4j试图将这些(以及 Clojure 提倡的基于不可变/值的风格)移植到 Java 语言中。这可能是你所追求的。

Disclaimer: I am the developer of Pure4J

免责声明:我是 Pure4J 的开发者