gpt4 book ai didi

java - 为什么 join() 现在可以在这里工作?

转载 作者:行者123 更新时间:2023-12-01 18:29:19 25 4
gpt4 key购买 nike

我正在尝试在多个线程的帮助下对从 1 到 n 的所有数字求和。

这是我的主题:

public class MyThread implements Runnable {
//Limits
int lowerLimit;
int upperLimit;
MyInteger result;

//Constructor
public MyThread(int lowerLimit, int upperLimit, MyInteger result){
this.lowerLimit = lowerLimit;
this.upperLimit = upperLimit;
this.result = result;
}

@Override
public void run() {

//Sums up the numbers in the given interval
for(int i= lowerLimit; i <= upperLimit;i++){
result.add(i);
}
}

}

它获取上限和下限以及在所有线程之间共享的结果。

这是我的测试类:

public class Sum {

public static long sumThreads(int numberThreads, int n) {

Thread[] threads = new Thread[numberThreads];
MyInteger result = new MyInteger(0);

// Creates new threads and starts them
for (int i = 0; i < numberThreads; i++) {
threads[i] = new Thread(new MyThread(i * n / numberThreads + 1,
(i + 1) * n / numberThreads, result));
threads[i].start();
}

// Waits for all thread to continue with the return
for (int i = 0; i < threads.length; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result.getValue();
}

public static void main(String[] args) {
System.out.println(sumThreads(10, 1000));
}

}

如果我只使用一个线程,结果是正确的。如果我使用多个线程,结果有时是正确的,但大多数时候都太低 - 这意味着线程尚未完成计算。但这怎么可能呢?我的 for 循环等待每个线程完成,因此当所有线程计算完各自的部分后,该方法首先返回结果。

最诚挚的问候

编辑:

MyInteger 类如下所示:

公共(public)类MyInteger { 私有(private)多头值(value);

public MyInteger(int value) {
this.value = value;
}

public long getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}

public void add(int summand){
value += summand;
}

public void sub(int decr){
value -= decr;
}

public void increase(){
value++;
}

public void decrease(){
value--;
}
}

最佳答案

您的加入代码看起来正确。我怀疑您的代码遇到了竞赛危险:

Wiki page on Race Condition

当您有多个线程同时运行,并且所有线程都修改共享资源时,您需要确保它们在执行修改时具有独占访问权限。

作为确认这是数据争用的快速修复,请尝试将 synchronized 修饰符添加到您的 add() 方法中MyInteger 类。

最终发生的是(对于双线程示例):

  1. (假设 MyInteger 实例的初始值为 17。)
  2. 线程 1 调用 add(3)
  3. JVM(线程 1)读取/看到 MyInteger 有值17,并且在添加操作期间单独维护它
  4. 线程 2 调用 add(5)
  5. JVM(线程 2)读取/看到 MyInteger值为 17,在添加过程中单独维护该值操作
  6. JVM(线程 1 线程 2)递增各自的值值,因此线程 1 有 20,线程 2 有 22。
  7. JVM(线程 1)将 20 写回 MyInteger 内的原语
  8. JVM(线程 2)将 22 写回 MyInteger 内的原语

您现在已经丢失 add(3) 操作的结果,因为正确的原子操作将导致 25 作为最终结果值。

除了线程安全的重要性之外,最重要的是,即使涉及原语的简单加法操作也不会作为单个原子操作执行。相反,它在 JVM 内被分解为更小的步骤,这允许并发线程相互竞争。

这是 wiki 文章中(优秀)表格的屏幕截图,直观地演示了这一点:

enter image description here

关于java - 为什么 join() 现在可以在这里工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24982697/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com