为什么我需要同步这个变量

时间:2016-09-12 21:41:58

标签: java multithreading concurrency thread-safety concurrent-programming

我有4个线程,每个线程试图在链表中找到最大值。

这是我的主题类:

public class MyThread extends Thread {

    LinkedList<Integer> list;
    int max = Integer.MIN_VALUE;

    public MyThread(LinkedList<Integer> list) {
        this.list = list;
    }

    public void run() {
        synchronized (list) {       /* If I don't synchronize list, I get a NoSuchElementException at list.remove() */
            while (!list.isEmpty()) {
                int num = list.remove();

                if (num > max) {
                    max = num;
                }
            }
        }
    }
}

以下是使用main方法的类:

public class Application {

    public static void main(String args[]) throws InterruptedException {
        LinkedList<Integer> list = new LinkedList<Integer>();

        for (int i = 0; i < 10; i++) {
            list.add(i);
        }

        MyThread t1 = new MyThread(list);
        MyThread t2 = new MyThread(list);
        MyThread t3 = new MyThread(list);
        MyThread t4 = new MyThread(list);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        t1.join();
        t2.join();
        t3.join();
        t4.join();

        System.out.println(t1.max);
        System.out.println(t2.max);
        System.out.println(t3.max);
        System.out.println(t4.max);
    }
}

在上面的代码中,我必须在run方法中同步list变量,否则我会在NoSuchElementException获得list.remove()。为什么会这样?

每个线程都不具有自己的列表,因此没有线程干扰吗?

由于

2 个答案:

答案 0 :(得分:1)

LinkedList不是线程安全的。因此,如果您使用多个线程对LinkedList进行操作,则需要外部同步。

你可以使用BlockingQueue,在这种情况下,poll()方法会派上用场。

答案 1 :(得分:1)

我将讨论@Rishi提出的问题的另一部分:

  

每个帖子都没有自己的列表,所以没有线程干扰吗?

简单的答案是:不,它没有。在Java中,当您将类类型的对象传递给构造函数或方法时,您不会传递obejct本身,而是传递给它的指针。如果要将链表的单独副本传递给每个线程,则需要使用LinkedList#Clone

如果您使用clone,那么当一个线程从其链接列表中删除一个整数时,它将不会从其他链接列表中删除。要正确地对此进行并列化,您应该使用包含所有数字的标准数组,并为每个线程分配此数组的一部分(即,线程1执行0-9,线程2执行10-19,线程3执行20-29,等等。)。在将内容存放到数组中之后创建的任何线程都可以看到数组的内容。

<小时/> 我还应该注意,你不应该扩展Thread。相反,扩展Runnable并将其传递给线程。此外,数组(列表)将优于4个单独的变量,因为它允许您以后轻松更改线程数。