2013-02-05 19 views
5

我有一个字符串列表(tagList),它需要在多个线程之间共享读取,所以我创建一个不可修改的版本并将它传递给线程,即时通讯不知道它是否线程安全,因为线程只读取列表我想应该没问题?is unmodifiableList线程安全吗?

还当我传递unmodifialble列表提供给线程,它通过一个单拷贝和共享通过螺纹或它创建多个拷贝和一个副本传递给每个线程?

这里是我的代码:

final List<String> tList = Collections.unmodifiableList(tagList); 
List<Future<Void>> calls = new ArrayList<Future<Void>>(); 

FileStatus[] fsta = _fileSystem.listStatus(p);  
for (FileStatus sta : fsta) { 
    final Path path = new Path(sta.getPath(), "data.txt"); 
    if (!_fileSystem.exists(path)) {   
     continue; 
    } 
    else { 
     calls.add(_exec.submit(new Callable<Void>() { 
      @Override 
      public Void call() throws Exception { 
       filterData(path, tList); 
       return null; 
      } 
     })); 
    } 
} 
+1

它是线程安全的。 – jdb

回答

6

这完全取决于底层列表是否在读取操作上是线程安全的。不可修改的列表只是将所有读取调用(例如size(),get (int)等)传递到底层列表,而无需额外的同步。

想象,例如,List实现其高速缓存哈希码代替在每次所需的时间来计算它的。对于这种实现,hashCode()方法实际上不是只读的,因为它可能会修改内部缓存的哈希码值。

又如链表的香料,它可以缓存参考与它的索引一起持续访问的条目,所以进一步尝试访问附近的元素将被更快地进行。对于这样的实现,方法get (int)将不会是只读的,因为它更新缓存的引用和索引,因此可能不是线程安全的。

+1

而底层的'List'可能会被修改。如果不安全地发布,推测也是不安全的。 –

+0

底层列表可能被修改的事实与线程安全无关。 –

+3

我不关注。如果正在读取的是不同于'unmodifiedList'的线程修改了基础'List',即使对基础'List'的读操作不会导致任何内部修改,这也将是多线程访问。 –

2

它是线程安全的(因为它不能进行修改)。它通过相同的副本。

然而,包裹清单(tagList)仍然不是线程安全的。在共享期间,您不得修改包装列表。 unmodifiableList()返回的列表的唯一原因是安全的,因为修改不允许通过它来包装列表。

0

正如你所说这个清单是不可修改的;因此它将是线程安全的。

当你传递一个对象时,你实际上将引用传递给对象(而不是实际的对象)。由于只有一个副本,并且它没有被修改,所以它将保持线程安全。

只是一个谨慎;直接访问tagList。通过名为tList的包装不可修改集合始终访问它。这可以通过适当封装来实现。