来自这篇文章:use.shtml
公共类StoppableTask扩展线程{私有易失性布尔值pleaseStop;公共void (){ while (!pleaseStop) { //做一些事情.} tellMeToStop() { pleaseStop = true;}} 如果变量没有声明为易失性(而且没有其他同步),那么运行循环的线程在循环开始时缓存变量的值并不再读取它是合法的。
在Java 5或更高版本中:
最后一段是对的吗?
那么,线程究竟能在什么时候缓存pleaseStop变量的值(以及缓存时间)?在调用对象的StoppableTask函数(run,tellMeTpStop)之前?(最晚退出函数时,线程必须更新变量?)
您能告诉我关于这方面的文档/教程参考(Java 5或更高版本)吗?
更新:这是我在这个问题上发布的答案汇编:
在不使用volatile或synchronized的情况下,上面的程序实际上有两个问题:
线程可以缓存变量pleaseStop,因为线程刚启动时就不再更新它了。因此,循环将永远持续下去。这可以通过使用volatile或synchronized来解决。这种线程缓存机制在C中不存在。
2- java编译器可以优化代码,并将while(!pleaseStop) {...}替换为if (!pleaseStop) { while (true) {...}}。因此,循环将永远持续下去。同样,这可以通过使用volatile或synchronized来解决。这种编译器优化也存在于C中。
更多信息:https://www.ibm.com/developerworks/library/j-5things15/
发布于 2015-06-10 03:05:20
什么时候可以缓存?
至于你关于“什么时候可以缓存”这个值的问题,答案是“永远”。要理解这意味着什么,请继续读下去。处理器具有称为缓存的存储,这使得正在运行的线程能够通过从缓存而不是从内存读取来访问内存中的值。正在运行的线程也可以像将值写入内存一样写入此缓存。因此,只要线程正在运行,它就可以使用缓存来存储它正在使用的数据。必须显式地发生一些事情才能将值从缓存刷新到内存。对于单线程进程来说,这一切都很好,但是如果您有另一个线程,它可能试图从内存中读取数据,而另一个线程则是将数据插入到处理器缓存中,而不会刷新到内存。
它能缓存多长时间?
至于“多长时间”部分,不幸的是,除非你做些什么,否则答案是永远的。对所讨论的数据进行同步是从缓存强制刷新的一种方法,以便所有线程都能看到对该值的更新。有关引发刷新的方法的更多详细信息,请参见下一节。
文件呢?
至于“文档在哪里”的问题,一个很好的起点是这里。具体而言,对于如何强制刷新,java通过讨论一个操作(如数据写入)是否“发生在”另一个操作(如读取的数据)之前就提到了这一点。有关此问题的更多信息,请参见这里。
那volatile呢
volatile本质上阻止了上面描述的处理器缓存类型。这确保从其他线程中可以看到对变量的所有写入。为了了解更多,您在帖子中链接到的教程似乎是一个好的开始。
发布于 2015-06-10 03:20:56
发布于 2015-06-10 03:05:35
正式文档在Java规范(特别是17.4记忆模型 )第17节中。
正确的观点是从假设多线程代码不能工作开始,并试图强迫它工作,不管它喜欢与否。如果没有volatile声明或类似的声明,那么如果在另一个线程中发生这种情况,就不会强迫pleaseStop的read看到写入。
我同意Java在实践中的并发性建议。它很好地阐述了JLS材料对实际Java编程的影响。
https://stackoverflow.com/questions/30746273
复制相似问题