Java中易失性和同步的区别

发布于 2024-09-15 05:15:08 字数 775 浏览 3 评论 0 原文

我想知道在Java中将变量声明为易失性和始终访问synchronized(this)块中的变量之间有什么区别?

根据这篇文章 http://www.javamex.com/tutorials/synchronization_volatile.shtml有很多话要说,有很多不同之处,但也有一些相似之处。

我对这条信息特别感兴趣:

...

  • 对易失性变量的访问永远不会被阻塞:我们只进行简单的读取或写入,因此与同步块不同,我们永远不会持有任何锁;
  • 因为访问易失性变量永远不会持有锁,所以它不适合我们想要读取-更新-写入作为原子操作的情况(除非我们准备“错过更新”) ”);

读取-更新-写入是什么意思?写入不是也是更新吗?或者它们只是意味着更新是依赖于读取的写入?

最重要的是,什么时候声明变量volatile比通过synchronized块访问它们更合适?对于依赖于输入的变量使用 volatile 是一个好主意吗?例如,有一个名为 render 的变量,它是通过渲染循环读取并由按键事件设置的?

I am wondering at the difference between declaring a variable as volatile and always accessing the variable in a synchronized(this) block in Java?

According to this article http://www.javamex.com/tutorials/synchronization_volatile.shtml there is a lot to be said and there are many differences but also some similarities.

I am particularly interested in this piece of info:

...

  • access to a volatile variable never has the potential to block: we're only ever doing a simple read or write, so unlike a synchronized block we will never hold on to any lock;
  • because accessing a volatile variable never holds a lock, it is not suitable for cases where we want to read-update-write as an atomic operation (unless we're prepared to "miss an update");

What do they mean by read-update-write? Isn't a write also an update or do they simply mean that the update is a write that depends on the read?

Most of all, when is it more suitable to declare variables volatile rather than access them through a synchronized block? Is it a good idea to use volatile for variables that depend on input? For instance, there is a variable called render that is read through the rendering loop and set by a keypress event?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

空心↖ 2024-09-22 05:15:08

重要的是要了解线程安全有两个方面。

  1. 执行控制和
  2. 内存可见性

第一个与控制代码何时执行(包括执行指令的顺序)以及是否可以并发执行有关,第二个与已完成的操作对内存的影响何时发生有关对其他线程可见。由于每个 CPU 和主内存之间都有多个级别的高速缓存,因此运行在不同 CPU 或内核上的线程在任何给定时刻都可以以不同的方式查看“内存”,因为允许线程获取主内存的私有副本并在其上工作。

使用synchronized可防止任何其他线程获取同一对象的监视器(或锁),从而防止所有受同步保护的代码块 >在同一个对象上并发执行。同步创建一个“发生在”内存屏障,从而导致内存可见性约束,使得在某个线程释放锁之前所做的任何事情出现给另一个随后获取锁的线程在获取锁之前发生了相同的锁定。实际上,在当前的硬件上,这通常会导致在获取监视器时刷新 CPU 缓存,并在释放监视器时写入主内存,这两者(相对)昂贵。

另一方面,使用 易失性 会强制对易失性变量的所有访问(读或写)发生在主内存中,从而有效地将易失性变量排除在 CPU 缓存之外。这对于某些仅要求变量可见性正确并且访问顺序并不重要的操作非常有用。使用易失性还改变了longdouble的处理,要求对它们的访问是原子的;在某些(较旧的)硬件上,这可能需要锁,但在现代 64 位硬件上则不需要。在 Java 5+ 的新 (JSR-133) 内存模型下,易失性的语义已得到加强,在内存可见性和指令排序方面几乎与同步一样强大(请参阅 http://www.cs.umd.edu/users/pugh/java/memoryModel /jsr-133-faq.html#易失性)。出于可见性的目的,对易失性字段的每次访问都相当于半次同步。

在新的内存模型下,易失性变量仍然不能相互重新排序。不同之处在于,现在不再那么容易对它们周围的正常字段访问进行重新排序。写入易失性字段具有与监视器释放相同的内存效应,并且从易失性字段读取具有与监视器获取相同的内存效应。实际上,因为新的内存模型对易失性字段访问与其他字段访问(无论是否易失性)的重新排序施加了更严格的限制,因此线程 A 在写入易失性字段 f 时可以看到的任何内容 在读取 f 时对线程 B 可见。

-- JSR 133(Java 内存模型)常见问题解答

因此,现在两种形式的内存屏障(在当前的 JMM 下)都会导致指令重新排序屏障,从而阻止编译器或运行时跨屏障重新排序指令。在旧的 JMM 中,易失性并不能阻止重新排序。这可能很重要,因为除了内存屏障之外,唯一的限制是,对于任何特定线程,代码的净效果与指令精确地执行时的效果相同。它们在源中出现的顺序。

易失性的一种用途是用于动态重新创建共享但不可变的对象,许多其他线程在其执行周期的特定点引用该对象。一旦发布了重新创建的对象,就需要其他线程开始使用该对象,但不需要完全同步的额外开销以及随之而来的争用和缓存刷新。

// Declaration
public class SharedLocation {
    static public volatile SomeObject someObject=new SomeObject(); // default object
    }

// Publishing code
SharedLocation.someObject=new SomeObject(...); // new object is published

// Using code
// Note: do not simply use SharedLocation.someObject.xxx(), since although
//       someObject will be internally consistent for xxx(), a subsequent 
//       call to yyy() might be inconsistent with xxx() if the object was 
//       replaced in between calls.
private String getError() {
    SomeObject myCopy=SharedLocation.someObject; // gets current copy
    ...
    int cod=myCopy.getErrorCode();
    String txt=myCopy.getErrorText();
    return (cod+" - "+txt);
    }
// And so on, with myCopy always in a consistent state within and across calls
// Eventually we will return to the code that gets the current SomeObject.

具体来说,就是谈谈你的读-更新-写问题。考虑以下不安全代码:

public void updateCounter() {
    if(counter==1000) { counter=0; }
    else              { counter++; }
    }

现在,由于 updateCounter() 方法不同步,两个线程可能会同时进入该方法。在可能发生的情况有多种排列中,其中之一是线程 1 测试 counter==1000 并发现它为真,然后被挂起。然后线程 2 执行相同的测试,也看到它为真并被挂起。然后线程 1 恢复并将计数器设置为 0。然后线程 2 恢复并再次将计数器设置为 0,因为它错过了线程 1 的更新。即使线程切换没有像我所描述的那样发生,这种情况也可能发生,但这仅仅是因为两个不同的 CPU 内核中存在两个不同的计数器缓存副本,并且每个线程都在单独的内核上运行。就这一点而言,一个线程可以将计数器设置为一个值,而另一个线程可以将计数器设置为某个完全不同的值,只是因为缓存。

在这个例子中重要的是,变量counter从主内存读入缓存,在缓存中更新,并且仅在内存屏障发生或缓存内存发生时的某个不确定点写回主内存。需要做其他事情。使计数器易失性不足以保证此代码的线程安全,因为最大值的测试和赋值是离散操作,包括增量,它是一组非原子read+增量+写入机器指令,类似于:

MOV EAX,counter
INC EAX
MOV counter,EAX

仅当对它们执行的所有操作都是“原子”时,易失性变量才有用,例如我的示例,其中引用一个完全形成的对象只能被读取或写入(事实上,通常它只是从一个点写入)。另一个示例是支持写时复制列表的易失性数组引用,前提是仅通过首先获取对其引用的本地副本来读取该数组。

It's important to understand that there are two aspects to thread safety.

  1. execution control, and
  2. memory visibility

The first has to do with controlling when code executes (including the order in which instructions are executed) and whether it can execute concurrently, and the second to do with when the effects in memory of what has been done are visible to other threads. Because each CPU has several levels of cache between it and main memory, threads running on different CPUs or cores can see "memory" differently at any given moment in time because threads are permitted to obtain and work on private copies of main memory.

Using synchronized prevents any other thread from obtaining the monitor (or lock) for the same object, thereby preventing all code blocks protected by synchronization on the same object from executing concurrently. Synchronization also creates a "happens-before" memory barrier, causing a memory visibility constraint such that anything done up to the point some thread releases a lock appears to another thread subsequently acquiring the same lock to have happened before it acquired the lock. In practical terms, on current hardware, this typically causes flushing of the CPU caches when a monitor is acquired and writes to main memory when it is released, both of which are (relatively) expensive.

Using volatile, on the other hand, forces all accesses (read or write) to the volatile variable to occur to main memory, effectively keeping the volatile variable out of CPU caches. This can be useful for some actions where it is simply required that visibility of the variable be correct and order of accesses is not important. Using volatile also changes treatment of long and double to require accesses to them to be atomic; on some (older) hardware this might require locks, though not on modern 64 bit hardware. Under the new (JSR-133) memory model for Java 5+, the semantics of volatile have been strengthened to be almost as strong as synchronized with respect to memory visibility and instruction ordering (see http://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#volatile). For the purposes of visibility, each access to a volatile field acts like half a synchronization.

Under the new memory model, it is still true that volatile variables cannot be reordered with each other. The difference is that it is now no longer so easy to reorder normal field accesses around them. Writing to a volatile field has the same memory effect as a monitor release, and reading from a volatile field has the same memory effect as a monitor acquire. In effect, because the new memory model places stricter constraints on reordering of volatile field accesses with other field accesses, volatile or not, anything that was visible to thread A when it writes to volatile field f becomes visible to thread B when it reads f.

-- JSR 133 (Java Memory Model) FAQ

So, now both forms of memory barrier (under the current JMM) cause an instruction re-ordering barrier which prevents the compiler or run-time from re-ordering instructions across the barrier. In the old JMM, volatile did not prevent re-ordering. This can be important, because apart from memory barriers the only limitation imposed is that, for any particular thread, the net effect of the code is the same as it would be if the instructions were executed in precisely the order in which they appear in the source.

One use of volatile is for a shared but immutable object which is recreated on the fly, with many other threads taking a reference to the object at a particular point in their execution cycle. One needs the other threads to begin using the recreated object once it is published, but does not need the additional overhead of full synchronization and it's attendant contention and cache flushing.

// Declaration
public class SharedLocation {
    static public volatile SomeObject someObject=new SomeObject(); // default object
    }

// Publishing code
SharedLocation.someObject=new SomeObject(...); // new object is published

// Using code
// Note: do not simply use SharedLocation.someObject.xxx(), since although
//       someObject will be internally consistent for xxx(), a subsequent 
//       call to yyy() might be inconsistent with xxx() if the object was 
//       replaced in between calls.
private String getError() {
    SomeObject myCopy=SharedLocation.someObject; // gets current copy
    ...
    int cod=myCopy.getErrorCode();
    String txt=myCopy.getErrorText();
    return (cod+" - "+txt);
    }
// And so on, with myCopy always in a consistent state within and across calls
// Eventually we will return to the code that gets the current SomeObject.

Speaking to your read-update-write question, specifically. Consider the following unsafe code:

public void updateCounter() {
    if(counter==1000) { counter=0; }
    else              { counter++; }
    }

Now, with the updateCounter() method unsynchronized, two threads may enter it at the same time. Among the many permutations of what could happen, one is that thread-1 does the test for counter==1000 and finds it true and is then suspended. Then thread-2 does the same test and also sees it true and is suspended. Then thread-1 resumes and sets counter to 0. Then thread-2 resumes and again sets counter to 0 because it missed the update from thread-1. This can also happen even if thread switching does not occur as I have described, but simply because two different cached copies of counter were present in two different CPU cores and the threads each ran on a separate core. For that matter, one thread could have counter at one value and the other could have counter at some entirely different value just because of caching.

What's important in this example is that the variable counter was read from main memory into cache, updated in cache and only written back to main memory at some indeterminate point later when a memory barrier occurred or when the cache memory was needed for something else. Making the counter volatile is insufficient for thread-safety of this code, because the test for the maximum and the assignments are discrete operations, including the increment which is a set of non-atomic read+increment+write machine instructions, something like:

MOV EAX,counter
INC EAX
MOV counter,EAX

Volatile variables are useful only when all operations performed on them are "atomic", such as my example where a reference to a fully formed object is only read or written (and, indeed, typically it's only written from a single point). Another example would be a volatile array reference backing a copy-on-write list, provided the array was only read by first taking a local copy of the reference to it.

起风了 2024-09-22 05:15:08

易失性字段修饰符,而同步修饰代码块方法。因此,我们可以使用这两个关键字指定简单访问器的三种变体:

<代码> int i1;
    int geti1() {返回 i1;}

    易失性 int i2;
    int geti2() {返回 i2;}

    整数 i3;
    同步 int geti3() {返回 i3;}

geti1() 访问当前线程中当前存储在 i1 中的值。
线程可以拥有变量的本地副本,并且数据不必与其他线程中保存的数据相同。特别是,另一个线程可能已在其线程中更新了 i1,但其中的值当前线程可能与更新后的值不同。事实上,Java 有“主”内存的概念,这是保存变量当前“正确”值的内存。线程可以拥有自己的变量数据副本,并且线程副本可以与“主”内存不同。因此,事实上,i1 的“主”内存的值为 1,thread1 的值为 2 > 对于 i1thread2,如果 thread1i1 的值为 3 > 和 thread2 都更新了 i1,但这些更新的值尚未传播到“主”内存或其他线程。

另一方面,geti2() 有效地从“主”内存访问 i2 的值。不允许易失性变量拥有与“主”内存中当前保存的值不同的变量的本地副本。实际上,声明为 volatile 的变量必须使其数据在所有线程之间同步,以便每当您在任何线程中访问或更新该变量时,所有其他线程都会立即看到相同的值。通常,易失性变量比“普通”变量具有更高的访问和更新开销。通常允许线程拥有自己的数据副本是为了提高效率。

volitile 和synchronized 之间有两个区别。

首先,synchronized 获取并释放监视器上的锁,该锁一次只能强制一个线程执行代码块。这是同步的众所周知的方面。但synchronized也同步内存。事实上,synchronized 使整个线程内存与“主”内存同步。因此,执行 geti3() 会执行以下操作:

  1. 线程获取对象 this 监视器上的锁。
  2. 线程内存刷新其所有变量,即它的所有变量都从“主”内存中有效读取。
  3. 执行代码块(在本例中将返回值设置为 i3 的当前值,该值可能刚刚从“主”内存重置)。
  4. (对变量的任何更改现在通常都会写入“主”内存,但对于 geti3() 我们没有任何更改。)
  5. 线程释放对象 this 监视器上的锁。

因此,挥发性仅同步线程内存和“主”内存之间的一个变量的值,而synchronized则同步线程内存和“主”内存之间的所有变量的值,并锁定和释放监视器以启动。显然,同步可能比易失性有更多的开销。

http://javaexp.blogspot.com/2007/12/difference -在-挥发性-和.html之间

volatile is a field modifier, while synchronized modifies code blocks and methods. So we can specify three variations of a simple accessor using those two keywords:

    int i1;
    int geti1() {return i1;}

    volatile int i2;
    int geti2() {return i2;}

    int i3;
    synchronized int geti3() {return i3;}

geti1() accesses the value currently stored in i1 in the current thread.
Threads can have local copies of variables, and the data does not have to be the same as the data held in other threads.In particular, another thread may have updated i1 in it's thread, but the value in the current thread could be different from that updated value. In fact Java has the idea of a "main" memory, and this is the memory that holds the current "correct" value for variables. Threads can have their own copy of data for variables, and the thread copy can be different from the "main" memory. So in fact, it is possible for the "main" memory to have a value of 1 for i1, for thread1 to have a value of 2 for i1 and for thread2 to have a value of 3 for i1 if thread1 and thread2 have both updated i1 but those updated value has not yet been propagated to "main" memory or other threads.

On the other hand, geti2() effectively accesses the value of i2 from "main" memory. A volatile variable is not allowed to have a local copy of a variable that is different from the value currently held in "main" memory. Effectively, a variable declared volatile must have it's data synchronized across all threads, so that whenever you access or update the variable in any thread, all other threads immediately see the same value. Generally volatile variables have a higher access and update overhead than "plain" variables. Generally threads are allowed to have their own copy of data is for better efficiency.

There are two differences between volitile and synchronized.

Firstly synchronized obtains and releases locks on monitors which can force only one thread at a time to execute a code block. That's the fairly well known aspect to synchronized. But synchronized also synchronizes memory. In fact synchronized synchronizes the whole of thread memory with "main" memory. So executing geti3() does the following:

  1. The thread acquires the lock on the monitor for object this .
  2. The thread memory flushes all its variables, i.e. it has all of its variables effectively read from "main" memory .
  3. The code block is executed (in this case setting the return value to the current value of i3, which may have just been reset from "main" memory).
  4. (Any changes to variables would normally now be written out to "main" memory, but for geti3() we have no changes.)
  5. The thread releases the lock on the monitor for object this.

So where volatile only synchronizes the value of one variable between thread memory and "main" memory, synchronized synchronizes the value of all variables between thread memory and "main" memory, and locks and releases a monitor to boot. Clearly synchronized is likely to have more overhead than volatile.

http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html

各自安好 2024-09-22 05:15:08

多线程有 3 个主要问题:

  1. 竞争条件

  2. 缓存/陈旧内存

  3. 编译器和CPU优​​化

易失性可以解决2& 3、但是解决不了1。synchronized/显式锁可以解决1、2& 3.

详细说明

  1. 考虑这个线程不安全代码:

x++;

虽然它可能看起来像一个操作,但它实际上是 3:从内存中读取 x 的当前值,将 1 添加到并将其保存回内存中。如果几个线程尝试同时执行此操作,则操作的结果是不确定的。如果 x 最初是 1,那么在 2 个线程操作代码之后,它可能是 2,也可能是 3,具体取决于哪个线程在控制权转移到另一个线程之前完成了操作的哪一部分。这是一种竞争条件

在代码块上使用 synchronized 使其成为原子 - 这意味着它使得 3 个操作就像同时发生,并且另一个线程无法介入其中并干涉。因此,如果 x 为 1,并且 2 个线程尝试执行 x++,我们知道最终将等于 3。因此它解决了竞争条件问题。

synchronized (this) {
   x++; // no problem now
}

x 标记为 易失性 不会使 x++; 原子化,因此它不能解决此问题。

  1. 此外,线程有自己的上下文 - 即它们可以缓存主内存中的值。这意味着一些线程可以拥有变量的副本,但它们对其工作副本进行操作,而不在其他线程之间共享变量的新状态。

考虑在一个线程上,x = 10;。稍后,在另一个线程中,x = 20;x 值的更改可能不会出现在第一个线程中,因为另一个线程已将新值保存到其工作内存中,但尚未将其复制到主内存中。或者它确实将其复制到主内存,但第一个线程尚未更新其工作副本。因此,如果现在第一个线程检查 if (x == 20),答案将为 false

将变量标记为“易失性”基本上告诉所有线程仅在主内存上执行读写操作。 Synchronized 告诉每个线程在进入块时从主内存更新其值,并在退出块时将结果刷新回主内存。

请注意,与数据竞争不同,过时的内存并不那么容易(重新)生成,因为无论如何都会发生主内存的刷新。

  1. 编译器和 CPU 可以(线程之间没有任何形式的同步)将所有代码视为单线程。这意味着它可以查看一些代码,这在多线程方面非常有意义,并将其视为单线程,而单线程则没有那么有意义。因此,如果它不知道该代码设计为在多个线程上工作,它可以查看代码并决定对其进行重新排序,甚至完全删除其中的某些部分,以进行优化。

考虑以下代码:

boolean b = false;
int x = 10;

void threadA() {
    x = 20;
    b = true;
}

void threadB() {
    if (b) {
        System.out.println(x);
    }
}

您可能认为 threadB 只能打印 20(或者如果在将 b 设置为 true 之前执行 threadB if-check,则根本不打印任何内容),如 b 仅在 x 设置为 20 后才设置为 true,但编译器/CPU 可能决定重新排序 threadA,在这种情况下 threadB 也可以打印 10。将 b 标记为易失性确保它不会被重新排序(或在某些情况下被丢弃)。这意味着 threadB 只能打印 20(或者什么也不打印)。将方法标记为同步将获得相同的结果。另外,将变量标记为 易失性 只能确保它不会被重新排序,但它之前/之后的所有内容仍然可以重新排序,因此同步可能更适合某些场景。

请注意,在 Java 5 新内存模型之前,易失性并没有解决这个问题。

There are 3 main issues with multithreading:

  1. Race Conditions

  2. Caching / stale memory

  3. Compiler and CPU optimisations

volatile can solve 2 & 3, but can't solve 1. synchronized/explicit locks can solve 1, 2 & 3.

Elaboration:

  1. Consider this thread unsafe code:

x++;

While it may look like one operation, it's actually 3: reading the current value of x from memory, adding 1 to it, and saving it back to memory. If few threads try to do it at the same time, the result of the operation is undefined. If x originally was 1, after 2 threads operating the code it may be 2 and it may be 3, depending on which thread completed which part of the operation before control was transferred to the other thread. This is a form of race condition.

Using synchronized on a block of code makes it atomic - meaning it make it as if the 3 operations happen at once, and there's no way for another thread to come in the middle and interfere. So if x was 1, and 2 threads try to preform x++ we know in the end it will be equal to 3. So it solves the race condition problem.

synchronized (this) {
   x++; // no problem now
}

Marking x as volatile does not make x++; atomic, so it doesn't solve this problem.

  1. In addition, threads have their own context - i.e. they can cache values from main memory. That means that a few threads can have copies of a variable, but they operate on their working copy without sharing the new state of the variable among other threads.

Consider that on one thread, x = 10;. And somewhat later, in another thread, x = 20;. The change in value of x might not appear in the first thread, because the other thread has saved the new value to its working memory, but hasn't copied it to the main memory. Or that it did copy it to the main memory, but the first thread hasn't updated its working copy. So if now the first thread checks if (x == 20) the answer will be false.

Marking a variable as volatile basically tells all threads to do read and write operations on main memory only. synchronized tells every thread to go update their value from main memory when they enter the block, and flush the result back to main memory when they exit the block.

Note that unlike data races, stale memory is not so easy to (re)produce, as flushes to main memory occur anyway.

  1. The complier and CPU can (without any form of synchronization between threads) treat all code as single threaded. Meaning it can look at some code, that is very meaningful in a multithreading aspect, and treat it as if it’s single threaded, where it’s not so meaningful. So it can look at a code and decide, in sake of optimisation, to reorder it, or even remove parts of it completely, if it doesn’t know that this code is designed to work on multiple threads.

Consider the following code:

boolean b = false;
int x = 10;

void threadA() {
    x = 20;
    b = true;
}

void threadB() {
    if (b) {
        System.out.println(x);
    }
}

You would think that threadB could only print 20 (or not print anything at all if threadB if-check is executed before setting b to true), as b is set to true only after x is set to 20, but the compiler/CPU might decide to reorder threadA, in that case threadB could also print 10. Marking b as volatile ensures that it won’t be reordered (or discarded in certain cases). Which mean threadB could only print 20 (or nothing at all). Marking the methods as syncrhonized will achieve the same result. Also marking a variable as volatile only ensures that it won’t get reordered, but everything before/after it can still be reordered, so synchronization can be more suited in some scenarios.

Note that before Java 5 New Memory Model, volatile didn’t solve this issue.

我不是你的备胎 2024-09-22 05:15:08

synchronized

是用于保护方法或代码块的关键字。通过将方法设为同步,您可以实现两件事。

  1. 同一对象上两次执行同步方法永远不会运行
  2. 对象状态的变化对其他线程可见

volatile是变量访问修饰符,它强制所有线程获取该对象的最新值来自主存的变量。所有线程都可以同时访问易失性变量值,而无需任何锁定。

使用易失性变量的一个很好的例子:Date 变量。

假设您已将 Date 变量设为易失性。您不需要不同的线程为同一变量显示不同的时间。访问该变量的所有线程始终从主内存获取最新数据,以便所有线程显示真实的(实际)日期值。

Lawrence Dol 清楚地解释了您的读写更新查询

关于您的其他查询

什么时候声明变量 volatile 比通过同步访问它们更合适?

如果您认为所有线程都应该获取变量的实际值,则必须使用 volatile像上面介绍的数据示例一样实时。

对于依赖于输入的变量使用 volatile 是一个好主意吗?

答案将与第一个查询中的相同。

synchronized

is keyword used to guard a method or code block. By making method as synchronized , you achieve two things.

  1. Two executions of synchronized methods on the same object never run
  2. Change in the object state is visible to other threads

volatile is variable access modifier which forces all threads to get latest value of the variable from main memory. All threads can access volatile variable value at same time with out any locks.

A good example to use volatile variable : Date variable.

Assume that you have made Date variable volatile. You don't need different threads showing different time for same variable. All the threads, which access this variable always get latest data from main memory so that all threads show real (actual) Date value.

Lawrence Dol cleary explained your read-write-update query.

Regarding your other queries

When is it more suitable to declare variables volatile than access them through synchronized?

You have to use volatile if you think all threads should get actual value of the variable in real time like Data example covered above.

Is it a good idea to use volatile for variables that depend on input?

Answer will be same as in first query.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文