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

时间:2011-09-16 19:34:25

标签: java multithreading linked-list

说明我的问题的代码:

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中有一个。

2 个答案:

答案 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)。