Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么我需要同步这个变量_Java_Multithreading_Concurrency_Thread Safety_Concurrent Programming - Fatal编程技术网

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

Java 为什么我需要同步这个变量,java,multithreading,concurrency,thread-safety,concurrent-programming,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(

我有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;
                }
            }
        }
    }
}
公共类MyThread扩展线程{
链接列表;
int max=整数的最小值;
公共MyThread(链接列表){
this.list=列表;
}
公开募捐{
synchronized(list){/*如果我不同步list,我会在list.remove()处得到一个NoSuchElementException*/
而(!list.isEmpty()){
int num=list.remove();
如果(数值>最大值){
max=num;
}
}
}
}
}
这是一个包含主要方法的类:

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);
    }
}
公共类应用程序{
公共静态void main(字符串args[])引发InterruptedException{
LinkedList=新建LinkedList();
对于(int i=0;i<10;i++){
列表.添加(i);
}
MyThread t1=新的MyThread(列表);
MyThread t2=新的MyThread(列表);
MyThread t3=新的MyThread(列表);
MyThread t4=新的MyThread(列表);
t1.start();
t2.start();
t3.start();
t4.开始();
t1.join();
t2.连接();
t3.join();
t4.join();
系统输出打印项次(t1最大值);
系统输出打印项数(t2最大值);
系统输出打印项次(t3最大值);
系统输出打印项次(t4最大值);
}
}
在上面的代码中,我必须在run方法中同步
list
变量,否则我将在
list.remove()
处得到一个
NoTouchElementException
。为什么会这样

不是每个线程都有自己的列表,所以没有线程干扰吗


谢谢,LinkedList不是线程安全的。因此,如果使用多个线程在LinkedList上操作,则需要外部同步


您可以使用
BlockingQueue
,它的poll()方法在这种情况下很方便。

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


您可以使用
BlockingQueue
,其poll()方法在本例中非常方便。

我将解决@Rishi所解决问题的另一部分:

不是每个线程都有自己的列表,所以没有线程干扰吗

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

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



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

我将解决@Rishi所解决问题的另一部分:

不是每个线程都有自己的列表,所以没有线程干扰吗

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

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



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

每个
MyThread
构造函数都使用相同的列表引用调用,因此所有线程都将使用相同的列表。假设您将
列表
传递到每个
线程
,为什么你会认为每一个都有自己的副本?特别是黑体字,上面写着“注意,这个实现是不同步的。”。Java是按值传递的,对象的值(比如你的列表)是它的引用。请参阅:每个
MyThread
构造函数都是使用相同的列表引用调用的,因此所有线程都将使用相同的列表。既然您将
列表
传递到每个
线程
,为什么您会认为每个线程都有自己的副本?尤其是粗体位,它表示“注意此实现未同步”.Java是按值传递的,对象(如列表)的值是其引用。请参阅:这不仅仅是因为它不是线程安全的:
isEmpty()
hasNext()
不是原子执行的,也就是说,另一个线程可以钳制并窃取导致
isEmpty()
返回false的元素+1对于
BlockingQueue
。这不仅仅是因为它不是线程安全的:
isEmpty()
hasNext()
不是自动执行的,也就是说,另一个线程可以进入并窃取导致
isEmpty()
返回false的元素+1用于阻塞队列。