Java 为什么我需要同步这个变量
我有4个线程,每个线程都试图在链表中找到最大值 这是我的线程类: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(
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用于阻塞队列。