为什么我需要同步这个变量
Why do I need to synchronize this variable
我有 4 个线程,每个线程都试图在链表中找到最大值。
这是我的帖子class:
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;
}
}
}
}
}
这是 class 的主要方法:
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);
}
}
在上面的代码中,我必须在 运行 方法中同步 list
变量,否则我会在 list.remove()
处得到一个 NoSuchElementException
。为什么会这样?
不是每个线程都有自己的列表所以没有线程干扰吗?
谢谢
LinkedList 不是线程安全的。因此,如果您使用多个线程对 LinkedList 进行操作,则需要外部同步。
您可以使用 BlockingQueue
,其 poll() 方法在这种情况下会派上用场。
我将解决@Rishi 解决的问题的不同部分:
Doesn't each thread have it's own list so there is no thread interference?
简单的回答是:不,不是。在 Java 中,当您将 class 类型的对象传递给构造函数或方法时,您传递的不是对象本身,而是指向它的指针。如果要将链表的单独副本传递给每个线程,则需要使用LinkedList#Clone。
如果你使用clone,那么当一个线程从它的链表中移除一个整数时,它不会从其他链表中移除。为了正确地并行化它,您应该使用一个包含所有数字的标准数组,并将该数组的一部分分配给每个线程(即线程 1 执行 0-9,线程 2 执行 10-19,线程 3 执行 20-29, ETC。)。数组的内容对于在数组中存放内容后创建的任何线程都是可见的。
我还应该注意,您不应该扩展 Thread。相反,扩展 Runnable 并将其传递给线程。此外,一个数组(列表)比 4 个单独的变量更好,因为它允许您稍后轻松更改线程数。
我有 4 个线程,每个线程都试图在链表中找到最大值。
这是我的帖子class:
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;
}
}
}
}
}
这是 class 的主要方法:
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);
}
}
在上面的代码中,我必须在 运行 方法中同步 list
变量,否则我会在 list.remove()
处得到一个 NoSuchElementException
。为什么会这样?
不是每个线程都有自己的列表所以没有线程干扰吗?
谢谢
LinkedList 不是线程安全的。因此,如果您使用多个线程对 LinkedList 进行操作,则需要外部同步。
您可以使用 BlockingQueue
,其 poll() 方法在这种情况下会派上用场。
我将解决@Rishi 解决的问题的不同部分:
Doesn't each thread have it's own list so there is no thread interference?
简单的回答是:不,不是。在 Java 中,当您将 class 类型的对象传递给构造函数或方法时,您传递的不是对象本身,而是指向它的指针。如果要将链表的单独副本传递给每个线程,则需要使用LinkedList#Clone。
如果你使用clone,那么当一个线程从它的链表中移除一个整数时,它不会从其他链表中移除。为了正确地并行化它,您应该使用一个包含所有数字的标准数组,并将该数组的一部分分配给每个线程(即线程 1 执行 0-9,线程 2 执行 10-19,线程 3 执行 20-29, ETC。)。数组的内容对于在数组中存放内容后创建的任何线程都是可见的。
我还应该注意,您不应该扩展 Thread。相反,扩展 Runnable 并将其传递给线程。此外,一个数组(列表)比 4 个单独的变量更好,因为它允许您稍后轻松更改线程数。