在什么条件下,非易失性变量的写入是否会被其他线程看不到?我可以强制这些条件用于实验目的吗?

dev*_*obf 6 java multithreading volatile non-volatile

我最近在SO和其他地方读过很多关于线程内存管理的内容,特别是volatile关键字的使用.然而,我开始对这个概念有相当的自信,为了充分理解它所具有的效果,我想尝试并运行一些实验来说明它.

这是我的设置:我有一个生产者线程(它从麦克风读取音频数据,与我之前的问题相关,但实际数据无关紧要),它将数据传递byte[]给单独的消费者线程.线程之间共享数据的方式是我实验中的主要变量:我尝试了一个ArrayBlockingQueue; 我尝试过共享volatile byte[]引用(本博客文章中array = array推荐的自引用); 我也尝试了一个没有自我参考的普通非易失性.两个线程也会在数据写入时将数据写入磁盘.byte[]

我希望发现,在运行一段时间之后,非易失性byte[]版本在生产者试图共享的数据与消费者读取数据之间的差异会因为某些内存写入时间不可见而导致数据不一致由于为确保发布内存写入所采取的预防措施,其他两个版本将由每个线程记录完全相同的数据.然而,无论我使用何种方法,我都会发现100%的准确率.

我已经可以想到为什么会发生这种情况的几种可能性,但我的主要问题是: 在什么条件下写入非易失性变量看不见另一个线程,据我所知,这是完整的观点volatile?我可以强制这些条件用于实验目的吗?

到目前为止我的想法是:

  • 也许这两个线程在同一个内核上运行并共享相同的缓存,因此内存写入立即可见?
  • 也许CPU负载是一个因素?在看到任何问题之前,我可能需要很多线程都做不同的事情?
  • 也许我需要等待更长时间:也许这些问题非常罕见?

任何人都可以建议我如何设计这样的实验或解释为什么我的想法有缺陷?

非常感谢.

ass*_*ias 5

在x86上的代码中,您将无法轻松观察到缺少障碍的影响,因为它具有相当强大的内存模型。但这并不意味着相同的代码不会在不同的体系结构上中断。在x86上,通常需要使用JIT编译器并帮助它进行可变变量(例如,变量提升)所不允许的优化。

在具有热点7u25服务器的本机上,以下代码在变量为非易失性的情况下永不结束,但在变量为非易失性的情况下会立即停止。您可能需要根据机器来更改睡眠延迟。

public class Test {

    static /* volatile */ boolean done = false;

    public static void main(String[] args) throws Exception {
        Runnable waiter = new Runnable() {
            @Override public void run() {
                while(!done);
                System.out.println("Exited loop");
            }
        };
        new Thread(waiter).start();
        Thread.sleep(100); //wait for JIT compilation
        done = true;
        System.out.println("done is true");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @gstackoverflow编译器设置为什么源语言级别?实现接口方法是在Java 6或更高版本上有效使用`@ Override`,但在Java 5中是不允许的(只有超类方法的真正重写才能在5中使用注释)。 (2认同)