我知道ArrayList
不是线程安全的,我见过很多人推荐
在(Collections.synchronizedList)
转换它。我需要创建一个系统,将ArrayList
转换为(Collections.synchronizedList)
,然后再转回ArrayList
。但首先我需要在a
中插入b
。
问题是我不知道如何从(Collections.synchronizedList)
转换为ArrayList
,当我尝试插入以下元素时出现错误:
public List<Object> a;
public List<ArrayList<Object>> b;
a = Collections.synchronizedList(new ArrayList<Object>());
b = Collections.synchronizedList(b);
当我尝试以下命令时会抛出异常:
b.add(id, (ArrayList<Object>) a);
java.base / java.util.Collections $ SynchronizedRandomAccessList无法强制转换为java.base / java.util.ArrayList
答案 0 :(得分:1)
有一个ArrayList
构造函数需要Collection
:
ArrayList<Object> arrayList = new ArrayList<>(a);
但是,将b
的类型更改为List<List<Object>>
可能更合理:
public List<ArrayList<Object>> b;
b.add(id, a);
答案 1 :(得分:1)
您最好将b
变量更改为:
public List<List<Object>> b;
并不依赖于具体的实现。它可以传递您想要的任何List
实现 - ArrayList
或Collections.SynchronizedList
。
否则,如果您不想更改字段类型(我不建议这样做),您可以使用复制构造函数:
b.add(2, new ArrayList<>(a));
或Stream API方法:
b.add(2, a.stream().collect(Collectors.toCollection(ArrayList::new)));
答案 2 :(得分:0)
这很简单。您的b
变量的类型为:
List<ArrayList<Object>> b
因此它包含ArrayList<Object>
类型而非List<Object>
类型的元素。因此,当您尝试插入a
时,编译器会抱怨,因为a
不是ArrayList<Object>
类型(但它从来没有)。您已使用
a = Collections.synchronizedList(...);
方法Collections#synchronizedList
不返回ArrayList
,它返回List
。
将您的b
对象更改为
List<List<Object>> b
您将可以插入a
。
或者,您需要再次明确地将a
转换为ArrayList
。例如,使用。
ArrayList<Object> resultA = new ArrayList<>(a);
然后插入resultA
。给定的构造函数创建一个新的ArrayList
,它添加给定集合的所有元素。
答案 3 :(得分:0)
a)小心,Collections.synchronizedList()不会使您的列表完全是线程安全的,它只是同步您的操作。如果您有多个线程读取和写入列表,如果您不知道自己在做什么,可能仍会遇到ConcurrentModificationException。如果您想要更好的线程安全性,请使用CopyOnWriteArrayList
。例如,如果一个线程将项添加到List,而另一个线程迭代,则会破坏除CopyOnWriteArrayList之外的任何List实现,无论它是否包含在Collections.synchronizedList()中。
b)Collections.synchronizedList()是原始列表周围的decorator。即你的ArrayList仍然存在于装饰器内部。您不需要将其复制回来,只需保留对原始ArrayList变量的引用。您对同步列表所做的每个更改都会传播到ArrayList。另一方面:为什么需要ArrayList?一个好的api将接受任何List类型。依赖ArrayList作为实现类型违反了至少一个Effective Java规则(第52项:通过其接口引用对象)。因此,除非您针对显式需要ArrayList的API进行编码,否则只需使用同步列表(将字段类型更改为List<List<Object>>
)。