jjzjj

java,线程何时(以及多长时间)可以缓存非 volatile 变量的值?

coder 2024-03-19 原文

来自这篇文章:http://www.javamex.com/tutorials/synchronization_volatile_typical_use.shtml

public class StoppableTask extends Thread {
  private volatile boolean pleaseStop;

  public void run() {
    while (!pleaseStop) {
      // do some stuff...
    }
  }

  public void tellMeToStop() {
    pleaseStop = true;
  }
}

If the variable were not declared volatile (and without other synchronization), then it would be legal for the thread running the loop to cache the value of the variable at the start of the loop and never read it again.

在 Java 5 或更高版本中:

最后一段是否正确?

那么,线程究竟在什么时候可以缓存 pleaseStop 变量的值(以及多长时间)?就在调用对象的 StoppableTask 函数之一(runtellMeTpStop)之前? (并且线程最迟在退出函数时必须更新变量?)

你能给我指出关于这个(Java 5 或更高版本)的文档/教程引用吗?


更新:这是我对这个问题发布的答案的汇编:

在不使用volatilesynchronized的情况下,上面的程序实际上有两个问题:

1- 线程可以缓存变量pleaseStop,从线程启动的第一刻起就不会再更新它。因此,循环将永远持续下去。这可以通过使用 volatilesynchronized 来解决。 C 中存在这种线程缓存机制。

2- java编译器可以优化代码,将while(!pleaseStop) {...}替换为if (!pleaseStop) { while (true) {... }}。因此,循环将永远持续下去。同样,这可以通过使用 volatilesynchronized 来解决。这种编译器优化也存在于 C 中。

更多信息: https://www.ibm.com/developerworks/library/j-5things15/

最佳答案

什么时候可以缓存?

至于您关于“何时可以缓存”该值的问题,答案是“总是”。要了解这意味着什么,请继续阅读。处理器具有称为高速缓存的存储空间,这使得正在运行的线程可以通过从高速缓存而不是从内存中读取来访问内存中的值。正在运行的线程也可以写入此缓存,就好像它正在将值写入内存一样。因此,只要线程在运行,它就可以使用缓存来存储它正在使用的数据。必须明确地发生某些事情才能将值从缓存刷新到内存。对于单线程进程,这一切都很好,但如果你有另一个线程,它可能会尝试从内存中读取数据,而另一个线程正在插入读取并将其写入处理器缓存而不刷新到内存.

能缓存多长时间?

至于“持续多长时间”部分 - 不幸的是,答案是永远的,除非您对此采取措施。同步相关数据是强制从缓存中刷新的一种方法,以便所有线程都能看到值的更新。有关引起同花顺的方法的更多详细信息,请参阅下一节。

一些文档在哪里?

至于“文档在哪里”的问题,一个好的起点是 here .对于具体如何强制刷新,java 通过讨论一个操作(例如数据写入)是否似乎“发生在”另一个操作(例如数据读取)来引用这一点。有关更多信息,请参阅 here .

volatile 怎么样?

volatile 实质上阻止了上述处理器缓存类型。这确保对变量的所有写入对其他线程都是可见的。要了解更多信息,您在帖子中链接到的教程似乎是一个好的开始。

关于java,线程何时(以及多长时间)可以缓存非 volatile 变量的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30746273/

有关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 - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  4. 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

  5. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  6. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

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

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

  8. 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/

  9. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  10. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

随机推荐