说明我的问题的代码:
public class Linkedlisttest {
public static void main(String[] args) {
Linkedlisttest test = new Linkedlisttest();
test.go(args);
}
public void go(String[] args) {
int cpus = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor tpe = new ThreadPoolExecutor(cpus, cpus * 2, 1L,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
String numbersarray[] = {"one", "two", "three", "four", "five"};
LinkedList<String> numbers = new LinkedList(Arrays.asList(numbersarray));
for (int index = 0; index < 2; index++) {
tpe.execute(new removeNumbers(numbers, index));
}
}
class removeNumbers implements Runnable {
LinkedList<String> localnumbers;
int index;
public removeNumbers(LinkedList<String> localnumbers, int index) {
this.localnumbers = localnumbers;
this.index = index;
}
@Override
public void run() {
System.out.println(localnumbers.size() + " Thread#: " + index);
while (localnumbers.size() > 0) {
System.out.println(localnumbers.removeFirst() + " Thread#: " + index);
}
}
}
}
和输出(在哪个线程删除了哪个元素时有所不同):
5 Thread#: 0
5 Thread#: 1
one Thread#: 0
three Thread#: 0
four Thread#: 0
five Thread#: 0
two Thread#: 1
我希望{"one", "two", "three", "four", "five"}
被删除两次,每个线程一次。但是,似乎removeNumbers
Runnables共享相同的localnumbers
LinkedList。为什么会这样?我的理解是,我创建了两个localnumbers
的单独实例,每个removeNumbers
Runnable中有一个。
答案 0 :(得分:5)
您将对同一LinkedList<String>
的引用传递给两个构造函数调用,因此每个localnumbers
指向相同的List
。这就是为什么两个都从同一个List
删除,因为你还没有真正复制它。
你想要做的事情是:
LinkedList<String> numbers = new LinkedList(Arrays.asList(numbersarray));
for (int index = 0; index < 2; index++) {
LinkedList<String> numbersCopy = new LinkedList<String>(numbers);
tpe.execute(new removeNumbers(numbersCopy, index));
}
有更有效的方法来制作这些副本。请注意,即使使用相同数组对Arrays.asList()的两次调用也不足以真正创建副本,因为该方法返回由数组支持的List
。您将需要在上面的循环中创建List
的副本,或者使用System.arraycopy()在开头复制数组:
String[] numbersarray = {"one", "two", "three", "four", "five"};
String[] numbersarray2 = new String[numbersarray.length];
System.arraycopy(numbersarray, 0, numbersarray2, 0, numbersarray.length);
答案 1 :(得分:2)
忽必烈是对的。如果您希望每个 removeNumbers 实例在其自己的列表上运行,则必须进行复制。所以你 removeNumbers 构造函数会创建一个列表的副本进行处理。为了使这更好/更安全,你应该传入一个ImmutableList(Guava)或一个不可修改的List(通过Collections)。