Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/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 8 ForkJoin未解释的输出_Java_Multithreading_Concurrency_Java 8_Fork Join - Fatal编程技术网

Java 8 ForkJoin未解释的输出

Java 8 ForkJoin未解释的输出,java,multithreading,concurrency,java-8,fork-join,Java,Multithreading,Concurrency,Java 8,Fork Join,我在玩ForkJoin框架和Java8acculateAndget函数。下面的程序产生了一个我无法解释的输出。你能吗 这不是家庭作业。这是Cay S.Horstmann的《真正不耐烦的人的JavaSE8》一书中的一个练习。这是一本好书 如果您提供一个函数,该函数应该对其参数进行操作,即 final String longestString = observed.accumulateAndGet(x, maxBy((str1, str2) -> observed.get().leng

我在玩
ForkJoin
框架和Java8
acculateAndget
函数。下面的程序产生了一个我无法解释的输出。你能吗

这不是家庭作业。这是Cay S.Horstmann的《真正不耐烦的人的JavaSE8》一书中的一个练习。这是一本好书


如果您提供一个函数,该函数应该对其参数进行操作,即

final String longestString = observed.accumulateAndGet(x,
    maxBy((str1, str2) -> observed.get().length() - x.length()));
严重违反了功能API的合同
AccumerateAndGet
将提供有关指定操作的原子更新,但不提供有关函数中另一个
get
操作的原子更新

不清楚您为什么这样做,因为实现正确的功能是很简单的:

final String longestString = observed.accumulateAndGet(x,
    maxBy((str1, str2) -> str1.length() - str2.length()));


请注意,在修复代码后,您仍然可能会观察到与之前记录的两个值不同的结果,因为
acgregateandget
为您提供了原子更新,但此原子性不会扩展到调用
acgregateandget
之前执行的日志记录操作。执行原子更新时,
AtomicReference
的记录内容可能已过时。但由于更新合同和您提供的运算符,生成的
字符串
的大小至少与您以前看到的最大值相同

此外,请记住,日志操作的感知顺序并不能说明执行更新操作的实际顺序

您可以更好地了解更改代码时发生的情况,如下所示:

public static String updateLongestString(AtomicReference<String> observed, String x) {

    final String longestString = observed.accumulateAndGet(x, maxBy((str1, str2) -> {
        LOGGER.info("Received str1: {}, str2: {}", str1, str2);
        return str1.length() - str2.length();
    }));

    LOGGER.info("New observed: {}.", longestString);

    return longestString;
}
publicstaticstringupdateLongestString(观察到原子引用,字符串x){
最终字符串longestString=observed.acgregateAndget(x,maxBy((str1,str2)->{
info(“收到的str1:{},str2:{}”,str1,str2);
返回str1.length()-str2.length();
}));
info(“新观察:{}.”,longestString);
返回最长的字符串;
}

感谢您的详细回复。有几件事我想说(如果格式不正确,很抱歉):*“如果您提供了一个函数,该函数应该对它的参数进行操作”-通常情况下,这不是真的,因为lambdas可以操作任何有效的final。*
acgregateAndget
的Javadoc表示“应用函数时,当前值作为第一个参数,给定的更新作为第二个参数。”。这就是我使用
get
的原因。但是现在想想,在
get
调用上没有任何保护措施。你把lambdas可以做什么和API的契约意味着什么弄混了。的文档中明确指出:“该函数应该没有副作用,因为当尝试的更新由于线程之间的争用而失败时,它可能会重新应用。”API没有要求您使用lambda实现
BinaryOperator
,事实上,您没有这样做。因此,原则上,您可以做的比lambda表达式允许的更多,但是……您对API的看法是正确的,但是
get
如何产生任何副作用呢?它不是递增/递减计数器。顺便说一句,我接受了你的答案,因为这是唯一一个写得很清楚的答案。在这种特殊情况下,效果相当有限。由于可能同时进行更新,额外的
get
调用可能会收到与第一个参数不同的值,但在这种情况下,后续的
cas
操作仍将失败。因此,可能发生的最糟糕的事情是,需要的重试次数比需要的要多(您使用
volatile
语义有效地执行了更多的读取,从而减慢了原子更新的速度)。但一般来说,最好将函数实现为实函数,即依赖于参数和常量,但不依赖于并发可变值。顺便说一句。我的示例违反了合同,日志记录也是一种副作用,但它只是为了帮助理解发生了什么,不应该出现在这种形式的生产代码中。
final String longestString = observed.accumulateAndGet(x,
    maxBy((str1, str2) -> observed.get().length() - x.length()));
final String longestString = observed.accumulateAndGet(x,
    maxBy((str1, str2) -> str1.length() - str2.length()));
final String longestString =
    observed.accumulateAndGet(x, maxBy(comparingInt(String::length)));
public static String updateLongestString(AtomicReference<String> observed, String x) {

    final String longestString = observed.accumulateAndGet(x, maxBy((str1, str2) -> {
        LOGGER.info("Received str1: {}, str2: {}", str1, str2);
        return str1.length() - str2.length();
    }));

    LOGGER.info("New observed: {}.", longestString);

    return longestString;
}