关于多线程:Java集合的不可修改包装器会使它们线程安全吗?

关于多线程:Java集合的不可修改包装器会使它们线程安全吗?

Does the unmodifiable wrapper for java collections make them thread safe?

我需要使ArrayLists线程的ArrayList安全。 我也不能让客户对集合进行更改。 不可修改的包装器会使其线程安全吗,或者我需要在集合上使用两个包装器?


这取决于。包装器只会阻止对其包装的集合进行更改,而不是对集合中的对象进行更改。如果您有一个ArrayLists的ArrayList,则全局列表及其每个元素列表都需要单独包装,并且您可能还需要为这些列表的内容做些事情。最后,您必须确保原始列表对象没有更改,因为包装器仅阻止通过包装器引用而不是原始对象的更改。

在这种情况下,您不需要同步包装器。


关于一个相关主题-我已经看到了几条建议使用同步集合以实现线程安全的回复。
使用集合的同步版本不会使其具有"线程安全性"-尽管在组合两个操作时每个操作(插入,计数等)都受到互斥锁的保护,但不能保证它们会自动执行。
例如,以下代码不是线程安全的(即使具有同步队列):

1
2
3
4
if(queue.Count > 0)
{
   queue.Add(...);
}

不可修改的包装器仅阻止更改其适用的列表的结构。如果此列表包含其他列表,并且您有尝试修改这些嵌套列表的线程,那么您将无法避免发生并行修改风险。


如果安全地发布了不可修改的视图,并且发布了不可修改的视图之后,则永远都不会修改可修改的原始文档(包括集合中递归包含的所有对象!),它将是线程安全的。

如果您想继续修改原始图,则可以创建集合对象图的防御性副本并返回该图的不可修改视图,或者使用固有的线程安全列表作为开头,然后返回该图的不可修改视图。 那。

如果您以后仍然打算不同步地访问List,则不能返回unmodifiableList(synchonizedList(theList))。 如果在多个线程之间共享可变状态,则所有线程在访问该状态时必须在相同的锁上进行同步。


根据定义,不可变对象是线程安全的(假设没有人保留对原始集合的引用),因此不需要同步。

使用Collections.unmodifiableList()包装外部ArrayList
防止客户端更改其内容(从而使其成为线程)
安全),但内部ArrayList仍然可变。

也使用Collections.unmodifiableList()包装内部ArrayList
防止客户更改其内容(从而使他们
线程安全),这就是您所需要的。

让我们知道此解决方案是否会引起问题(开销,内存使用情况等);
其他解决方案可能适用于您的问题。 :)

编辑:当然,如果列表被修改,它们不是线程安全的。我假设没有进一步的编辑。


我相信,因为UnmodifiableList包装器将ArrayList存储到最终字段,所以只要创建包装器后未修改列表,包装器上的任何读取方法都将看到构造包装器时的列表,并且只要包装器内部的可变ArrayList不被修改(包装器无法防范)。


通过查看"集合"源,看起来"不可修改"不会使其同步。

1
2
3
4
static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
                 implements Set<E>, Serializable;

static class UnmodifiableCollection<E> implements Collection<E>, Serializable;

同步类包装器中有一个互斥对象来完成同步部分,因此看起来您需要同时使用两者。还是自己滚!


不知道我是否理解您要做什么,但我会说大多数情况下的答案是"否"。

如果将ArrayList和ArrayList设置为ArrayList和ArrayList,则在创建后就永远不能更改外部列表和内部列表(并且在创建过程中,只有一个线程可以访问内部列表和外部列表),它们可能被包装器线程安全(如果同时,外部列表和内部列表以无法修改的方式包装)。 ArrayList上的所有只读操作很可能是线程安全的。但是,Sun不能保证它们是线程安全的(也不适用于只读操作),因此,即使它可能现在就可以工作,但将来可能会中断(如果Sun创建了一些内部数据缓存来更快地访问它们)。例)。


在以下情况下这是必需的:

  • 仍然有对原始可修改列表的引用。
  • 该列表可能会通过迭代器进行访问。
  • 如果仅打算按索引从ArrayList中读取,则可以假定这是线程安全的。

    如有疑问,请选择同步包装器。


    推荐阅读

      修改时间命令linux?

      修改时间命令linux?,时间,系统,命令,大陆,国家,信息,时区,终端,时分,日期,如

      linux中路径修改命令?

      linux中路径修改命令?,系统,命令,首次,工作,名称,目录,文件,环境变量,路径,

      linux修改脚本的命令?

      linux修改脚本的命令?,系统,密码,服务,工作,工具,环境,信息,百度,代码,脚本,

      linux修改命令所属组?

      linux修改命令所属组?,系统,信息,档案,工具,状态,文件,命令,设备,检测,环境,l

      linux下修改端口命令?

      linux下修改端口命令?,代码,服务,端口,系统,文件,编辑,后果,命令,字段,下面,L

      linux修改名称命令?

      linux修改名称命令?,系统,名称,图片,查询系统,代码,名字,命令,用户,文件名,

      linux修改时区的命令?

      linux修改时区的命令?,时间,系统,大陆,国家,标准,时区,命令,日期,终端,方法,L

      linux网络修改命令?

      linux网络修改命令?,地址,网络,系统,工作,服务,代码,管理,命令,工具,设备,Lin

      linux修改内存命令?

      linux修改内存命令?,系统,信息,标准,工具,数据,在线,内存,命令,分区,大小,Lin

      linux修改用户名命令?

      linux修改用户名命令?,系统,密码,查询系统,代码,数字,用户名,命令,第三,电

      linux命令换行后修改?

      linux命令换行后修改?,服务,系统,本行,代码,环境,工作,命令,文件,终端,字符,

      linux修改端口号命令?

      linux修改端口号命令?,代码,服务,系统,端口,工作,邮箱,文件,编辑,命令,后果,

      linux命令换行后修改?

      linux命令换行后修改?,服务,系统,本行,代码,环境,工作,命令,文件,终端,字符,

      linux修改端口号命令?

      linux修改端口号命令?,代码,服务,系统,端口,工作,邮箱,文件,编辑,命令,后果,

      linux修改锁屏命令?

      linux修改锁屏命令?,时间,系统,密码,名称,软件,电脑,工具,命令,终端,快捷键,l

      linux修改时钟命令?

      linux修改时钟命令?,时间,系统,大陆,国家,时区,命令,信息,终端,时钟,日期,lin

      linux的修改权限命令?

      linux的修改权限命令?,系统,信息,档案,网站,权限,文件,数字,命令,目录,选项,l

      linux命令ip修改?

      linux命令ip修改?,地址,系统,代码,密码,网络,信息,服务,设备,工具,命令,linux

      linux多线程下载命令?

      linux多线程下载命令?,软件,工具,平台,中心,系统,代理,网络,网站,手机,官方

      linux命令测试客户端?

      linux命令测试客户端?,地址,系统,网络,工具,工作,分析,环境,命令,下行,资料,l