简体   繁体   English

LinkedList多线程在Runnable中创建单独的实例

[英]LinkedList multithreading creating separate instances in Runnable

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> 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);
            }
        }
    }
}

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. 我期望{"one", "two", "three", "four", "five"}被删除两次,每个线程一次。 However, it seems like the removeNumbers Runnables are sharing the same localnumbers LinkedList. 但是,似乎removeNumbers Runnables共享相同的localnumbers LinkedList。 Why does this happen? 为什么会这样? My understanding is that I've created two separate instances of localnumbers , one in each removeNumbers Runnable. 我的理解是,我创建了两个单独的localnumbers实例,每个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 . 您要在两个构造函数调用中传递对相同LinkedList<String>的引用,因此每个localnumbers都指向相同的List That's why both are removing from the same List , because you haven't actually copied it. 这就是为什么两者都从同一List中删除的原因,因为您实际上尚未复制它。

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. 请注意,即使使用同一数组对Arrays.asList()的两次调用也不足以真正创建副本,因为该方法返回的是由数组支持的List 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: 您将需要像上面的循环一样创建List副本,或者使用System.arraycopy()在开头复制数组:

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. 如果希望每个removeNumbers实例在其自己的列表上运行,则必须进行复制。 So you removeNumbers constructor would create a copy of the list for processing. 因此,您removeNumbers构造函数将创建列表的副本以进行处理。 To make this even better / safer you should pass in an ImmutableList (Guava) or an unmodifiable List (via Collections). 为了使它更好/更安全,您应该传递一个ImmutableList(Guava)或一个不可修改的List(通过Collections)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM