在今天的工作中,我遇到了volatileJava中的关键字.我不太熟悉它,我发现了这个解释:
鉴于该文章解释了相关关键字的详细信息,您是否使用过它,或者您是否曾经看到过以正确方式使用此关键字的情况?
我想知道在声明变量as volatile和始终访问synchronized(this)Java 中的块中的变量之间的区别?
根据这篇文章,http://www.javamex.com/tutorials/synchronization_volatile.shtml有很多要说的,但也有很多不同之处,但也有一些相似之处.
我对这条信息特别感兴趣:
...
- 对volatile变量的访问永远不会阻塞:我们只进行简单的读或写操作,因此与synchronized块不同,我们永远不会持有任何锁;
- 因为访问volatile变量永远不会持有锁,所以它不适合我们想要读取update-write作为原子操作的情况(除非我们准备"错过更新");
read-update-write是什么意思?写入也不是更新,还是仅仅意味着更新是依赖于读取的写入?
最重要的是,何时更适合声明变量volatile而不是通过synchronized块访问变量?使用volatile依赖于输入的变量是一个好主意吗?例如,有一个变量被称为render通过渲染循环读取并由按键事件设置?
我阅读了一些关于该volatile关键字的文章,但我无法弄清楚它的正确用法.你能告诉我在C#和Java中它应该用什么吗?
假设我有一个静态复杂对象,它由一个线程池定期更新,并在一个长时间运行的线程中或多或少地连续读取.对象本身总是不可变的,反映了最近的某种状态.
class Foo() { int a, b; }
static Foo theFoo;
void updateFoo(int newA, int newB) {
f = new Foo();
f.a = newA;
f.b = newB;
// HERE
theFoo = f;
}
void readFoo() {
Foo f = theFoo;
// use f...
}
Run Code Online (Sandbox Code Playgroud)
我至少不在乎我的读者是看到旧的还是新的Foo,但是我需要看到一个完全初始化的对象.IIUC,Java规范说没有HERE中的内存屏障,我可能会看到一个fb初始化但尚未提交到内存的对象.我的程序是一个真实世界的程序,它迟早会将内容提交到内存中,所以我不需要立即将新的值ofFoo提交到内存中(虽然它不会受到伤害).
您认为实现内存屏障最可读的方式是什么?如果需要,我愿意为了可读性而付出一点性能价格.我想我可以将赋值同步到Foo,这样可行,但是我不确定读取代码的人为什么这么做是非常明显的.我还可以同步新Foo的整个初始化,但这会引入更多实际需要的锁定.
你会如何编写它以使其尽可能可读?
对Scala版本的奖励荣誉:)
我已经阅读了这个答案,最后写了以下内容:
使用volatile可以完成的任何事情都可以通过同步来完成,但反之亦然.
目前尚不清楚.JLS 8.3.1.4定义了volatile字段,如下所示:
字段可以声明为volatile,在这种情况下,Java Memory Model可以确保所有线程都看到变量的一致值(第17.4节).
因此,volatile字段与内存可见性有关.另外,据我所提到的答案,读取和写入易失性字段是同步的.
同步反过来保证只有一个线程可以访问同步块.正如我所知,它与内存可见性无关.我错过了什么?
所以我刚刚学习了volatile关键字,同时为明天的TAing部分编写了一些示例.我写了一个快速程序来证明++和 - 操作不是原子的.
public class Q3 {
private static int count = 0;
private static class Worker1 implements Runnable{
public void run(){
for(int i = 0; i < 10000; i++)
count++; //Inner class maintains an implicit reference to its parent
}
}
private static class Worker2 implements Runnable{
public void run(){
for(int i = 0; i < 10000; i++)
count--; //Inner class maintains an implicit reference to its parent
}
}
public static void main(String[] args) throws InterruptedException {
while(true){ …Run Code Online (Sandbox Code Playgroud) 当一个线程读取volatile变量,它看到不仅仅是最新的变化挥发,而且代码的副作用,导致了变化
这在http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html中提到
有人可以提供一个例子吗?
这首先给我的印象是,读取volatile变量的线程将与writer线程同步并等待写入完成.但事实显然并非如此.
一个例子可以帮助很多,并非常感激.
谢谢,穆斯塔法
当我注意到一个可变字段用^:unsynchronized-mutable注释时,我正在研究一个clojure lib .Mutable是可变的,但我不知道未同步的部分意味着什么,所以我读了文档,其中包含:
请注意,可变字段非常难以正确使用,并且只是为了便于在Clojure本身中构建更高级别的构造,例如Clojure的引用类型.它们仅供专家使用 - 如果:volatile-mutable或:unynchronized-mutable的语义和含义对您来说不是很明显,那么您就不应该使用它们.
我无法得到细微差别:它是否说在实践中我选择哪个可变性注释无关紧要,或者人们应该忘记完全使用可变类型?
并且,为了好奇,在较低的抽象层次中,它们之间的语义差异是什么?
谢谢!
据我所知,如果我们将变量声明为volatile,那么它将不会存储在本地缓存中.每当线程更新值时,它都会更新到主存储器.因此,其他线程可以访问更新的值.
但是在下面的程序中,volatile和non-volatile变量都显示相同的值.
不会为第二个线程更新volatile变量.任何人都可以解释为什么testValue没有改变.
class ExampleThread extends Thread {
private int testValue1;
private volatile int testValue;
public ExampleThread(String str){
super(str);
}
public void run() {
if (getName().equals("Thread 1 "))
{
testValue = 10;
testValue1= 10;
System.out.println( "Thread 1 testValue1 : " + testValue1);
System.out.println( "Thread 1 testValue : " + testValue);
}
if (getName().equals("Thread 2 "))
{
System.out.println( "Thread 2 testValue1 : " + testValue1);
System.out.println( "Thread 2 testValue : " + testValue);
}
}
}
public class VolatileExample {
public …Run Code Online (Sandbox Code Playgroud) java ×9
volatile ×7
concurrency ×2
c# ×1
clojure ×1
java-me ×1
keyword ×1
mutability ×1
scala ×1
synchronized ×1