多线程Pi计算器不一致的答案

时间:2017-05-19 01:30:15

标签: java multithreading

我正在尝试创建一个简单的程序来计算PI,并教我自己多线程的工作原理。每次我运行程序时,我都会得到不同的PI答案。我假设它与每次以不同顺序运行的Threads有关,但是在我输出我的答案之前我在每个Thread上调用了Thread.join(),所以我不确定为什么计算的顺序是在会影响我的最终答案。我也尝试创建一个我已命名为add的同步方法,以便更新Pi变量线程安全,并将volatile修饰符添加到我的pi变量,但这并没有阻止问题的发生。我所拥有的代码全部保存在一个类中,即

public class Pi implements Runnable{
    static volatile double pi = 0;
    static long numRects = 100;
    static int rectsPerThread = 1   ;
    static double width = 1.0 / numRects;
    long start, end;

    public Pi(long start, long end){
        this.start = start;
        this.end = end;
    }

    @Override
    public void run(){
        double tmp = 0;
        for(long i = start; i < end; i++){
            tmp += Math.sqrt(1.0 - Math.pow(width * i, 2)) * width;
        }
        add(tmp);
    }

    private synchronized void add(double partOfPi){
        pi += partOfPi;
    }

    public static void main(String[] args){
        Thread[] threads = new Thread[(int)(numRects / rectsPerThread)];
        double start = System.nanoTime();
        for(int i  = 0; i < threads.length; i++){
            threads[i] = new Thread(new Pi(i * rectsPerThread, i * rectsPerThread + rectsPerThread));
            threads[i].start();
        }

        for(Thread t : threads){
            try{
                t.join();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }

        pi *= 4;
        System.out.println(pi);
        System.out.printf("Ran in: %.4fms", (System.nanoTime() - start) / Math.pow(10, 6));
    }
}

我的问题如下:我的多线程错误导致每次都会返回不同的答案,我该怎么办呢?

1 个答案:

答案 0 :(得分:0)

以下,

var += expr;

不是原子操作。旧值被读取,递增和写回,因此它不是线程安全的。你需要用信号量来防范它。

import java.util.concurrent.Semaphore;
public class Pi implements Runnable{
    static double pi = 0;
    static long numRects = 100;
    static int rectsPerThread = 1;
    static double width = 1.0 / numRects;
    long start, end;
    private static final Semaphore s = new Semaphore(1);

    public Pi(long start, long end){
        this.start = start;
        this.end = end; 
    }

    @Override
    public void run(){
        for(long i = start; i < end; i++){
            try{
                s.acquire();
            }catch (InterruptedException IE){ 
                return;
            }
            pi += Math.sqrt(1.0 - Math.pow(width * i, 2)) * width;
            s.release();
        }
    }

    public static void main(String[] args){
        Thread[] threads = new Thread[(int)(numRects / rectsPerThread)];
        double start = System.nanoTime();
        for(int i  = 0; i < threads.length; i++){
            threads[i] = new Thread(new Pi(i * rectsPerThread, i * rectsPerThread + rectsPerThread));
            threads[i].start();
        }

        for(Thread t : threads){
            try{
                t.join();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }

        pi *= 4;
        System.out.println(pi);
        System.out.printf("Ran in: %.4fms", (System.nanoTime() - start) / Math.pow(10, 6));
    }
}