Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 线程运行方法内部使用的方法的同步_Java_Multithreading_Concurrency_Java 8 - Fatal编程技术网

Java 线程运行方法内部使用的方法的同步

Java 线程运行方法内部使用的方法的同步,java,multithreading,concurrency,java-8,Java,Multithreading,Concurrency,Java 8,我想对几组输入值执行并行计算。我是否需要同步计算(a,b,inputIndex)方法 private static final String FORMULA = "(#{a} + #{b}) * (#{a} + #{b} * #{b} - #{a})"; private List<Pair<Integer, Integer>> input = Arrays.asList( new ImmutablePair<>(1, 2), n

我想对几组输入值执行并行计算。我是否需要同步
计算(a,b,inputIndex)
方法

private static final String FORMULA = "(#{a} + #{b}) * (#{a} + #{b} * #{b} - #{a})";
private List<Pair<Integer, Integer>> input = Arrays.asList(
        new ImmutablePair<>(1, 2),
        new ImmutablePair<>(2, 2),
        new ImmutablePair<>(3, 1),
        new ImmutablePair<>(4, 2),
        new ImmutablePair<>(1, 5)
);
private List<String> output = new ArrayList<>(Arrays.asList("", "", "", "", ""));

public void calculate() {
    IntStream.range(0, input.size()).forEach(idx -> {
        Pair<Integer, Integer> pair = input.get(idx);

        Thread threadWrapper = new Thread(
                () -> this.calculate(pair.getLeft(), pair.getRight(), idx)
        );
        threadWrapper.start();
    });

    try {
        Thread.sleep(4000); // waiting for threads to finish execution just in case
        System.out.println("Calculation result => " + output);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private void calculate(Integer a, Integer b, int inputIndex) {
    System.out.println("Thread with index " + inputIndex + " started calculation.");
    Evaluator eval = new Evaluator();
    eval.putVariable("a", a.toString());
    eval.putVariable("b", b.toString());

    try {
        String result = eval.evaluate(FORMULA);
        Thread.sleep(3000);
        output.set(inputIndex, result);
        System.out.println("Thread with index " + inputIndex + " done.");
    } catch (EvaluationException | InterruptedException e) {
        e.printStackTrace();
    }
}
private static final String FORMULA=“(#{a}+#{b})*(#{a}+#{b}*#{b}-#{a})”;
私有列表输入=Arrays.asList(
新的不可变对(1,2),
新的不可变对(2,2),
新的不可变对(3,1),
新的不可变对(4,2),
新的不可变对(1,5)
);
私有列表输出=新的ArrayList(Arrays.asList(“,”,“,”,“,”,”);
公共空间计算(){
IntStream.range(0,input.size()).forEach(idx->{
Pair Pair=input.get(idx);
ThreadThreadWrapper=新线程(
()->this.calculate(pair.getLeft(),pair.getRight(),idx)
);
threadWrapper.start();
});
试一试{
sleep(4000);//等待线程完成执行,以防万一
System.out.println(“计算结果=>”+输出);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
私有void计算(整数a、整数b、整数inputIndex){
System.out.println(“带索引的线程”+inputIndex+“已开始计算”);
Evaluator eval=新的Evaluator();
eval.putVariable(“a”,a.toString());
eval.putVariable(“b”,b.toString());
试一试{
字符串结果=评估(公式);
睡眠(3000);
输出设置(输入索引、结果);
System.out.println(“带索引的线程”+inputIndex+“完成”);
}捕获(EvaluationException | InterruptedException e){
e、 printStackTrace();
}
}

因为如果
calculate
方法的代码在
run
方法的
Runnable
中,我就不需要这样做了。(另外,我认为我不需要同步收集,因为对于
输入
我只通过索引获取数据,对于
输出
我将元素放在特定位置)

重要的是要强调,尝试代码并获得正确的输出不足以证明程序的正确性,尤其是涉及多线程时。在您的情况下,它可能是偶然工作的,原因有两个:

  • 您的代码中有调试输出语句,即,
    System.out.println(…)
    ,它引入了线程同步,就像在参考实现中,
    PrintStream
    内部同步一样

  • 您的代码很简单,运行时间不够长,无法通过JVM进行深入优化

显然,如果在生产环境中使用类似的代码,这两个原因都可能消失


为了获得正确的程序,即使将
calculate(整数a、整数b、int-inputIndex)
更改为
synchronized
方法也是不够的。同步仅适用于在同一对象上同步线程之前建立关系

您的启动方法
calculate()
这个
实例上不同步,并且它也不执行任何其他足以与计算线程建立“先发生后发生”关系的操作(如调用
Thread.join()
。它只调用
Thread.sleep(4000)
,这显然不能保证其他线程在这段时间内完成。此外:

需要注意的是,
Thread.sleep
Thread.yield
都没有任何同步语义。特别是,在调用
Thread.sleep
Thread.yield
之前,编译器不必将寄存器中缓存的写入刷新到共享内存中,也不必重新加载值c调用
Thread.sleep
Thread.yield
后,在寄存器中进行ached

例如,在以下(断开的)代码片段中,假设
this.done
是一个非易失性的
字段:

编译器可以自由读取字段
this.done
一次,并在每次执行循环时重用缓存的值。这意味着循环永远不会终止,即使另一个线程更改了
this.done
的值

请注意,示例中所述的
this.done
也适用于列表的支持数组的数组元素。如果您没有使用不可变的
字符串
实例,效果可能会更糟


但是没有必要使整个方法
同步
,只有数据交换必须是线程安全的。最干净的解决方案是使整个方法没有副作用,即将签名改为
字符串计算(整数a、整数b)
并让该方法返回结果,而不是操作共享数据结构。如果该方法没有副作用,则不需要任何同步

调用方必须将结果值组合到
列表中
,但由于您已经在使用流API,此操作是免费的:

private static final String FORMULA = "(#{a} + #{b}) * (#{a} + #{b} * #{b} - #{a})";
private List<Pair<Integer, Integer>> input = Arrays.asList(
        new ImmutablePair<>(1, 2),
        new ImmutablePair<>(2, 2),
        new ImmutablePair<>(3, 1),
        new ImmutablePair<>(4, 2),
        new ImmutablePair<>(1, 5)
);

public void calculate() {
    List<String> output = input.parallelStream()
            .map(pair -> this.calculate(pair.getLeft(), pair.getRight()))
            .collect(Collectors.toList());
    System.out.println("Calculation result => " + output);
}

private String calculate(Integer a, Integer b) {
    System.out.println(Thread.currentThread()+" does calculation of ("+a+","+b+")");
    Evaluator eval = new Evaluator();
    eval.putVariable("a", a.toString());
    eval.putVariable("b", b.toString());

    try {
        String result = eval.evaluate(FORMULA);
        Thread.sleep(3000);
        System.out.println(Thread.currentThread()+" with ("+a+","+b+") done.");
        return result;
    } catch (EvaluationException | InterruptedException e) {
        throw new RuntimeException(e);
    }
}
private static final String FORMULA=“(#{a}+#{b})*(#{a}+#{b}*#{b}-#{a})”;
私有列表输入=Arrays.asList(
新的不可变对(1,2),
新的不可变对(2,2),
新的不可变对(3,1),
新的不可变对(4,2),
新的不可变对(1,5)
);
公共空间计算(){
列表输出=输入。并行流()
.map(pair->this.calculate(pair.getLeft(),pair.getRight())
.collect(Collectors.toList());
System.out.println(“计算结果=>”+输出);
}
私有字符串计算(整数a、整数b){
System.out.println(Thread.currentThread()+“进行(“+a+”,“+b+”)的计算);
Evaluator eval=新的Evaluator();
eval.putVariable(“a”,a.toString());
eval.putVariable(“b”,b.toString());
private static final String FORMULA = "(#{a} + #{b}) * (#{a} + #{b} * #{b} - #{a})";
private List<Pair<Integer, Integer>> input = Arrays.asList(
        new ImmutablePair<>(1, 2),
        new ImmutablePair<>(2, 2),
        new ImmutablePair<>(3, 1),
        new ImmutablePair<>(4, 2),
        new ImmutablePair<>(1, 5)
);

public void calculate() {
    List<String> output = input.parallelStream()
            .map(pair -> this.calculate(pair.getLeft(), pair.getRight()))
            .collect(Collectors.toList());
    System.out.println("Calculation result => " + output);
}

private String calculate(Integer a, Integer b) {
    System.out.println(Thread.currentThread()+" does calculation of ("+a+","+b+")");
    Evaluator eval = new Evaluator();
    eval.putVariable("a", a.toString());
    eval.putVariable("b", b.toString());

    try {
        String result = eval.evaluate(FORMULA);
        Thread.sleep(3000);
        System.out.println(Thread.currentThread()+" with ("+a+","+b+") done.");
        return result;
    } catch (EvaluationException | InterruptedException e) {
        throw new RuntimeException(e);
    }
}