草庐IT

java - 在什么情况下其他线程看不到对非 volatile 变量的写入?我可以出于实验目的强制这样的条件吗?

coder 2024-03-31 原文

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

这是我的设置:我有一个生产者线程(它从麦克风读取音频数据,与我的 previous question 相关,但实际数据并不重要),它以 byte[]<> 到一个单独的消费者线程。线程之间共享数据的方式是我实验中的主要变量:我尝试了一个ArrayBlockingQueue;我尝试了一个共享的 volatile byte[] 引用(使用 array = array 自引用,如 this blog post 中所推荐);我还尝试了一个没有自引用的普通非 volatile byte[] 。两个线程同时将数据写入磁盘。

我希望发现,在运行一段时间后,非 volatile byte[] 版本会在生产者尝试共享的数据与生产者尝试共享的数据之间存在差异由于某些内存写入不及时可见,消费者读取数据,而其他两个版本将具有每个线程记录的完全相同的数据,因为采取了确保内存写入发布的预防措施。然而,碰巧的是,无论我使用什么方法,我都发现 100% 准确。

我已经想到了为什么会发生这种情况的几种可能性,但我的主要问题是:在什么情况下写入另一个线程看不到的非 volatile 变量,就目前而言我的理解是 volatile 的全部意义所在? 我可以出于实验目的强制这些条件吗?

目前我的想法是:

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

谁能建议我如何设计这样的实验或解释为什么我的想法有缺陷?

非常感谢。

最佳答案

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

下面的代码,在我有热点 7u25 服务器的机器上,如果变量是非 volatile 的,则永远不会结束,但如果是,则立即停止。您可能需要根据您的机器更改 sleep 延迟。

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");
    }
}

关于java - 在什么情况下其他线程看不到对非 volatile 变量的写入?我可以出于实验目的强制这样的条件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18491937/

有关java - 在什么情况下其他线程看不到对非 volatile 变量的写入?我可以出于实验目的强制这样的条件吗?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  3. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  8. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

随机推荐