我在Android中使用的外部库具有从另一个线程访问的对象的ArrayList。我的问题是我想以一种不会在另一个线程上引起空例外的方式从这个AarrayList中移动一些对象。
所以,我想要做的是:我有一个ArrayList ABCDEFGH,我想将F从其实际位置移动到第一个位置,因此ArrayList将变为FABCDEGH。请注意,我不能使用swap,因为每个其他对象都向右移动。
一个天真的实现是:
list.remove(F);
list.add(0,F);
但是这个实现导致另一个线程上的null异常,因为另一个线程是通过手写的计数循环来循环列表,所以由于竞争条件,线程循环可以在删除和添加F之间运行。我可以'使ArrayList步骤安全,因为我无法访问外部库。
是否有更好的方法可以在没有竞争条件的情况下进行此移动(从任何位置到Arraylist的任何位置)?请注意,不会修改ArrayList的大小。
答案 0 :(得分:3)
如果您拥有循环和交换代码,则可以同步列表中的两个操作。
// code for loop
for (int i = 0; i < length; i++) {
synchronized(list) {
letter = list.get(i);
}
// whatever else
}
// code for swap
synchronized(list) {
list.remove(F);
list.add(0,F);
}
<强>更新强>
我假设您需要循环线程来查看您在交换/循环代码中所做的更改。这是对的吗?
如果没有,他们可以简单地克隆/复制列表供您自己使用。
List copy = new ArrayList(list);
copy.remove(F);
copy.add(0,F);
答案 1 :(得分:0)
重新排序ArrayList中的对象,但不使用add()
,remove()
或任何其他可能改变大小的方法。
它可以完成,而不是非常优雅,如下:
Object temp = F;
for (int i = list.indexOf(F); i > 0; i--) {
list.set(i, list.get(i - 1));
}
list.set(0, temp);
但请注意,另一个线程中的循环可能会遇到错误顺序的对象,或者不同位置的同一对象。如果另一个线程添加或删除项目,那么这将无效。
我认为如果你不能同步列表,你或许不应该尝试从你的线程中修改它。