Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/322.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 演示不正确发布对象的问题_Java_Multithreading_Concurrency - Fatal编程技术网

Java 演示不正确发布对象的问题

Java 演示不正确发布对象的问题,java,multithreading,concurrency,Java,Multithreading,Concurrency,JCIP警告我们不要发布不正确的对象(请参阅)。如果对象是可变的,JVM可能会在其初始化完成之前决定发布该对象 那么代码呢 class Holder {public int h = 0;public Holder(int _h) {h = _h;}} a = new Holder(10); 可能变得有效 a = new Holder(); // inlined constructor a.h = 10; 然后,当不同的线程访问a.h时,假设它永远不能为0,则可能会失败 // Thread #

JCIP警告我们不要发布不正确的对象(请参阅)。如果对象是可变的,JVM可能会在其初始化完成之前决定发布该对象

那么代码呢

class Holder {public int h = 0;public Holder(int _h) {h = _h;}}
a = new Holder(10);
可能变得有效

a = new Holder();
// inlined constructor
a.h = 10;
然后,当不同的线程访问a.h时,假设它永远不能为0,则可能会失败

// Thread #1 executing
a = new Holder();
// Thread #2 preempts
if (a != null) System.out.println("result: "+(100/a.h)); // oops...
我试图证明这个问题。但是我写的代码没有演示它。我所做的是一个保持者

static class Holder {
    int h = 0;
    int dummy = 0;
    public Holder(int h) {
        // if construction takes time, maybe I have better chance creating the bug...
        for (long i=0;i<1000*1000;i++) {
            dummy += i*(-1+(i%2*2));
        }
        this.h = h;
    }
    public int verifyNonZero() {
        return 1/h;
    }
}
静态类持有者{
int h=0;
int-dummy=0;
公共持有人(int h){
//如果建设需要时间,也许我有更好的机会创造错误。。。

对于(长i=0;i来说,不能保证安全这一事实并不意味着在您的环境中一定会出问题

据我所知,没有证据表明这种行为可以在现代JVM上表现出来。但是,有证据表明一些较旧的JVM受到了影响:

还要注意,无序执行不仅可能由JVM引起,也可能由CPU引起。然而,x86 CPU的内存模型非常保守(),因此这种行为也不能由常用的CPU引起


因此,我认为在典型的现代环境中,您不太可能演示此问题。

您如何运行测试?[编辑:哦,您链接到了代码!]

JMM保证在给定的线程中,您将无法看到无序的情况——也就是说,如果同一个线程实例化
Holder
并检查它,它将永远不会看到未初始化的状态

因此,您必须在一个线程中实例化一个Holder,然后在另一个线程中看到它。如何共享该实例?常用方法(易失性静态、同步或线程安全集合等)在持有者被其实例化线程发布的时间和被另一个线程读取的时间之间建立一个before-before关系

如果您想要不安全的出版物,您的主要选择是:

  • 将其放入共享但非线程安全的集合中。这对您的测试来说有点风险,因为集合本身可能引发异常
  • 放入非易失性静态
  • 将其放入数组(不使用AtomicReferenceArray)

即使这样,你还是依赖于计时来出错。我没有像你这样幸运地用一个静态来复制这类比赛;我认为代码不够复杂,CPU无法进行奇特的缓存


IBM有一个实验性的javaagent,它故意尝试利用并发错误。不久前,我在一个故意造成线程危险的队列上给了它一次机会(我相信这是故意造成的死锁)。没有竞争,队列很少失败;有了竞争,大约30%的时间都会失败。我不确定竞争在内存可见性竞争中是好是坏。

也许你必须为Java打开一些优化标志。寻找它们?@AbhinavSarkar我想
-server
应该可以做到这一点。知道是什么吗我应该添加额外的标志吗?看看这个列表:是的,我知道,但是你对一个特定的相关标志有什么想法吗(例如增加永久空间对我没有帮助,是不是…)?我认为JCIP意味着这是一个在实践中可能出现的问题。是否有一个通用的JVM可以演示它?可能是Android或OpenJDK?@Elazar:这是一个“一次编写,到处运行”的原则-他们不能说“在这个特定环境中是安全的”,因为您的程序可以在不同的环境中运行,并且允许它们对操作进行重新排序。但是,由于没有证据表明现代环境中存在此问题,因此可能无法证明它。