java - 为什么需要同步这个变量

标签 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 变量,否则我会在 list.remove() 处得到 NoSuchElementException 。为什么会这样?

不是每个线程都有自己的列表,这样就不会出现线程干扰吗?

谢谢

最佳答案

我将解决 @Rishi 所解决的问题的不同部分:

Doesn't each thread have it's own list so there is no thread interference?

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

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

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

关于java - 为什么需要同步这个变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39459212/

相关文章:

c++ - Qt 5 : update QProgressBar during QThread work via signal

c# - 在另一个线程上创建 WPF 进度窗口

java - 如何检查线程是否完成了任务?

java - 使用 volatile 发布不可变对象(immutable对象)安全吗?

multithreading - Scala Future vs Thread 用于长时间运行的任务而没有结果

java - Flyway脚本不使用Spring Boot执行

Java 关闭 TCP/IP 连接

c++ - 无锁堆栈与原子

java - 将 NoSuchBeanDefinitionException 存储库引入服务

java - 在 JScrollpane 内动态更改 JPanel 中的内容可见性