线程安全问题-未得到预期的答案

ryoqjall  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(305)

我试图将一系列双精度浮点数相加,这些浮点数在数组中以字符串形式给出。这些数字的相加是在单独的后台线程中执行的。运行代码计算数字数组的总和,并给出系统计算所用的时间(以秒为单位)。
我不确定如何对此类实现同步和条件同步:

public class SerialAdder implements Adder {
    private String[] values;
    private double sum;
    private boolean ready = false;

    public void run() {
        synchronized (this) {
            sum = 0.0;

            for (int i = 0; i < values.length; i++) {
                sum = sum + Double.valueOf(values[i]);
            }

            ready = true;
        }
    }

    public synchronized void setValues(String[] values) {
        this.values = values;
    }

    public synchronized void setThreads(int threads) {
        // This does nothing since this is the single-threaded version.
    }

    public synchronized double getSum() {
        return sum;
    }
}

这一点不应更改,但在此仅供参考。

public interface Adder extends Runnable {

    void setValues(String[] values);
    void setThreads(int threads);
    double getSum();
}

这是主要的

import java.io.*;

public class Main {

    /**
     * All this data is "statistically initialized" and hence visibility to all threads in the running application.
     */
    private static final String[] DATA1 = {"1.0", "2.0", "3.0", "4.0"};
    private static final String[] DATA2 = {"100000000000000000000.0", "-100000000000000000000.0", "1.0", "2.0"};
    private static final String[] DATA3 = {"1.0", "2.0", "100000000000000000000.0", "-100000000000000000000.0"};

    /**
     * This is an Example of more complex "static initialization" that guarantees data visibility to all threads.
     */

    private static final String[] DATA4;

    static {

        /***TASK3: CHANGE THIS VALUE SO THAT YOUR COMPUTER TAKES SEVERAL SECONDS FOR THE SERIAL CASE***/
        final int POWER = 10;
        final int N = (int)Math.pow(2, POWER);
        DATA4 = new String[N];

        for (int i = 0; i < N; i++) {
            DATA4[i] = String.valueOf(1.0/N);
        }
    }

    public static void main(String[] args) throws InterruptedException, IOException {

        // Start the timer ...
        long startTime = System.currentTimeMillis();

        /***TASK 2 - CHANGE THIS LINE TO SEE HOW THE CODE BEHAVES WITH DIFFERENT DATA INPUTS.***/
        String[] values = DATA1;

        /***TASK 3 - CHANGE THE FOLLOWING SINGLE LINE TO CHANGE TO USING A MULTITHREADED VERSION OF THE ADDER.***/

        // This is an example of "programming to an interface" ... so only a single line
        // needs to be changed to change the implementation used in the rest of the code.

        Adder adder = new SerialAdder(); // = MultithreaderAdder();
        adder.setValues(values);

        new Thread(adder).start();

        System.out.println("Answer = " + adder.getSum());

        // Printed answer ... stop the timer.
        long endTime = System.currentTimeMillis();

        // Nanoseconds to seconds ...
        System.out.println("Time = " + (endTime - startTime)/1000.0 + " seconds.") ;

    }
}

以及多线程加法器:

public class MultithreadedAdder implements Adder {

    public void run() {};

    public void setValues(String[] values) {};

    public void setThreads(int threads) {};

    public double getSum() {
        return 0.0;
    }
}

我使用的是当前数据{“1.0”,“2.0”,“3.0”,“4.0”},所以期望答案是10.0,但是我得到的是0。

jv4diomz

jv4diomz1#

我建议简化一下:
放下枪 Adder 接口。实施 Callable 而不是接口。它允许您返回一个值。
我建议不要这样做 setThreads() 方法。给你的 Callable 示例到池 Executor .
如果数组中的其中一个字符串不作为 Double 你的总数会失败。你打算怎么办?我会有一个试试看的街区。

import java.util.Arrays;
import java.util.concurrent.Callable;

public class DoubleStreamAdder implements Callable<Double> {

    private final String [] values;

    public DoubleStreamAdder(final String [] v) {
        this.values = new String[v.length];
        System.arraycopy(v, 0, this.values, 0, v.length);
    }

    @Override
    public Double call() throws Exception {
        return Arrays.stream(this.values).mapToDouble(Double::valueOf).sum();
    }
}

您可以使用java函数式编程来完成所有这些,而不必使用类:请参阅我的 call() 方法。这就是你想做的。你写的代码越少,错误就越少。通过删除接口和类并编写一行代码,可以消除17行以上的代码。好多了。

相关问题