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

时间:2014-07-27 15:57:49

标签: java multithreading join

我试图在多个线程的帮助下总结从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类看起来像这样:

公共类MyInteger {     私人长期价值;

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--;
}
}

1 个答案:

答案 0 :(得分:4)

您的join代码看起来是正确的。我怀疑您的代码遇到race hazard

Wiki page on Race Condition

如果多个线程同时运行,所有修改共享资源,则需要确保在执行修改时它们具有独占访问权。

快速修复以确认这是数据竞争,请尝试将synchronized修饰符添加到add()类中的MyInteger方法。< / p>

最终发生了什么(对于双线程示例):

  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. 中的原语
  9. JVM(线程2)将22写回MyInteger
  10. 中的原语

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

    除了线程安全的重要性之外,除此之外最重要的一点是即使是涉及基元的简单加法操作也不会作为单个原子操作执行。相反,它被分解为JVM中的较小步骤,这允许并发线程竞赛相互对抗。

    以下是wiki文章中(优秀)表格的屏幕截图,用于直观地展示:

    enter image description here

相关问题