Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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发生在关系调用EANDWAIT之前_Java_Multithreading_Runnable_Happens Before_Invokeandwait - Fatal编程技术网

Java发生在关系调用EANDWAIT之前

Java发生在关系调用EANDWAIT之前,java,multithreading,runnable,happens-before,invokeandwait,Java,Multithreading,Runnable,Happens Before,Invokeandwait,我的问题与问题有关,这个问题已经有了答案: 是的,行为之间存在一种先发生后施加的关系 调用调用调用调用器的线程的 由此提交的可运行文件的EDT 我的问题有点笼统:是否有可能实现一个方法,比如invokeAndWait,这样它就可以正常工作,但不会强加一个发生在之前的关系?我所说的正常工作方法是指: 提交的Runnable保证只执行一次 提交的Runnable在特定线程上执行 该方法等待提交的Runnable的执行完成 该方法保证在提交的Runnable执行完成后返回 在我看来,要实现这一点,

我的问题与问题有关,这个问题已经有了答案:

是的,行为之间存在一种先发生后施加的关系 调用调用调用调用器的线程的 由此提交的可运行文件的EDT

我的问题有点笼统:是否有可能实现一个方法,比如
invokeAndWait
,这样它就可以正常工作,但不会强加一个发生在之前的关系?我所说的正常工作方法是指:

  • 提交的
    Runnable
    保证只执行一次
  • 提交的
    Runnable
    在特定线程上执行
  • 该方法等待提交的
    Runnable
    的执行完成
  • 该方法保证在提交的
    Runnable
    执行完成后返回

在我看来,要实现这一点,就必须建立“先发生后发生”的关系,还是我错了?如果是这样,请包括一个示例实现,以证明这一点。

这里最困难的要求是:

提交的
Runnable
保证只执行一次

使用非易失性(普通)字段将工作任务从提交者转移到执行者不会创建“先发生后执行”关系,但也不能保证执行者在所有时间或有限时间内看到任务。编译器将能够优化对该字段的分配,或者在运行时,执行器线程可能只从其缓存而不是从主存读取值

因此,对于使用Java8或更低版本的代码,我会说答案是“不,这样的
invokeAndWait
方法是不可能的”(可能使用本机代码除外)

但是,Java9添加了内存模式不透明。Doug Lea的页面“”详细描述了这一点,Doug Lea是(添加了此功能)的作者。最重要的是,不透明模式比volatile弱,但仍提供以下保证:

  • 进度。写入操作最终可见。
    […]
    例如,在构造中,某些变量x的唯一修改是一个线程以不透明(或更强)模式写入,
    x.setOpaque(this,1)
    ,而在
    中旋转的任何其他线程(x.getOpaque(this)!=1){}
    最终将终止。
    […]
    请注意,此保证在普通模式下不成立,在普通模式下,自旋循环可能(通常)无限循环[…]
<>当设计这样的<代码>调用和等待> <代码>方法之前,不必发生关系之前,还必须考虑在线程开始之前发生的动作发生在线程()中的第一个动作之前。因此,必须在构造操作之前启动工作线程

此外,还必须考虑“
final
字段语义”()。当
invokeAndWait
的调用者以lambda表达式的形式创建
Runnable
时,lambda对变量的捕获(据我理解)具有隐式
final
字段语义

如果是,请提供一个示例实现,以证明这一点

由于依赖于硬件和时间,使用示例证明或反驳线程安全性或发生在关系之前即使不是不可能,也是很困难的。然而,像这样的工具可以帮助实现这一点

下面是一个
invokeAndWait
的(简化的)潜在实现,它没有before关系。请注意,我并不完全熟悉Java内存模型,因此代码中可能存在错误

import java.util.concurrent.AtomicBoolean;
导入java.util.concurrent.AtomicReference;
类运算放大器{
//为了简单起见,假设每个任务都只有一个工作任务
//因此,由其他任务替换挂起的任务不是问题
private final AtomicReference nextTask=新的AtomicReference();
公共OpaqueExecutor(){
线程工作线程=新线程(()->{
while(true){
//使用getOpaque()不在关系之前创建
Runnable task=nextTask.getOpaque();
如果(任务==null){
//为了提高效率,请向JVM指示这正忙着等待
Thread.onSpinWait();
}否则{
//清除挂起的任务;这里的内存模式并不重要,因为我们只需要
//以确保此线程不会再次看到任务
nextTask.setPlain(空);
task.run();
}
}
}“工作线程”);
worker.setDaemon(true);
worker.start();
}
公共void调用器(Runnable Runnable){
//为简单起见,假设不存在可执行的挂起任务
//取而代之的是
//使用setOpaque(…)不创建发生在关系之前的事件
设置不透明(可运行);
}
私有静态类任务实现可运行{
private final AtomicBoolean isFinished=新的AtomicBoolean(false);
//一定不能是最终的,以防止发生之前的关系
//最终字段语义
私人可运行;
公共任务(可运行的可运行的){
this.runnable=runnable;
}
公开募捐{
试一试{
runnable.run();
}最后{
//使用setOpaque(…)不创建发生在关系之前的事件
isFinished.set不透明(true);
}
}
公共void join(){
//使用getOpaque()不在关系之前创建
而(!isFinished.get不透明()){
//为了提高效率,请向JVM指示这正忙着等待
Thread.onSpinWait();
}
}
}
public void invokeAndWait(可运行可运行){
任务任务=新任务(可运行);
调用器(任务);
task.join();
}
公共静态void main(字符串…参数){