Code that illustrates my problem:
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> loc开发者_JAVA技巧alnumbers;
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);
}
}
}
}
and the output (which varies somewhat in which thread removes what element):
5 Thread#: 0
5 Thread#: 1
one Thread#: 0
three Thread#: 0
four Thread#: 0
five Thread#: 0
two Thread#: 1
I'm expecting {"one", "two", "three", "four", "five"}
to get removed twice, once by each thread. However, it seems like the removeNumbers
Runnables are sharing the same localnumbers
LinkedList. Why does this happen? My understanding is that I've created two separate instances of localnumbers
, one in each removeNumbers
Runnable.
You're passing a reference to the same LinkedList<String>
into both constructor calls, so each localnumbers
is pointing to the same List
. That's why both are removing from the same List
, because you haven't actually copied it.
You will want to do something along the lines of:
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));
}
There are more efficient ways to make these copies. Note that even two calls to Arrays.asList() using the same array will not be enough to truly create copies, since that method returns a List
backed by the array. You will need to create copies of the List
as in the loop above, or else use System.arraycopy() to copy the array at the beginning:
String[] numbersarray = {"one", "two", "three", "four", "five"};
String[] numbersarray2 = new String[numbersarray.length];
System.arraycopy(numbersarray, 0, numbersarray2, 0, numbersarray.length);
Kublai is correct. If you want each removeNumbers instance to operate on it's own list you must make copies. So you removeNumbers constructor would create a copy of the list for processing. To make this even better / safer you should pass in an ImmutableList (Guava) or an unmodifiable List (via Collections).
精彩评论