0

This Q is looking for specific details on how exactly Java makes a volatile field visible.

The volatile keyword in Java is used for making a variable "actively" visible to the readers of that variable right after a write operation on it is done. This is one form of happens-before relationship-- makes the results of a write exposed to whoever accessing that memory location of that variable for some use. And when used, makes the read/write operations on that variable atomic-- for long & double as well-- R/W to every other var types are atomic already.

I'm looking to find out what Java does to make a variable value visible after a write operation?

Eg.: The following code is from one of the answers on this discussion:

public class Foo extends Thread {
  private volatile boolean close = false;
  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

Reads and writes to boolean literals are atomic. if the method close() above is invoked, it is an atomic operation to set the value of close as true even if it isn't declared as volatile.

What more volatile is doing in this code is making sure that a change to this value is seen the moment it happens.

How exactly volatile is achieving this?

by giving priority to threads with operations on a volatile variable? if so - how, in thread scheduling, or by making the threads-with-read-operations go look up a flag to see whether there's a writer-thread pending? I'm aware that "A write to a volatile field happens-before every subsequent read of that same field." Is it choosing among the threads, the one(s) that have a write operation on a volatile variable before giving CPU time to threads that only read?

If this is managed in thread scheduling level (which i doubt), then running a thread with a write on a volatile field has a bigger effect than it seems.

How exactly is Java managing visibility of volatile variables?

TIA.

4

2 回答 2

3

This is the comment from source code of OpenJDK about volatile

// ----------------------------------------------------------------------------
// Volatile variables demand their effects be made known to all CPU's
// in order.  Store buffers on most chips allow reads & writes to
// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode
// without some kind of memory barrier (i.e., it's not sufficient that
// the interpreter does not reorder volatile references, the hardware
// also must not reorder them).
//
// According to the new Java Memory Model (JMM):
// (1) All volatiles are serialized wrt to each other.  ALSO reads &
//     writes act as aquire & release, so:
// (2) A read cannot let unrelated NON-volatile memory refs that
//     happen after the read float up to before the read.  It's OK for
//     non-volatile memory refs that happen before the volatile read to
//     float down below it.
// (3) Similar a volatile write cannot let unrelated NON-volatile
//     memory refs that happen BEFORE the write float down to after the
//     write.  It's OK for non-volatile memory refs that happen after the
//     volatile write to float up before it.
//
// We only put in barriers around volatile refs (they are expensive),
// not _between_ memory refs (that would require us to track the
// flavor of the previous memory refs).  Requirements (2) and (3)
// require some barriers before volatile stores and after volatile
// loads.  

I hope it's helpful.

于 2014-10-05T17:04:27.863 回答
3

According to this :

http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile

Java's new memory model does this by

1) prohibiting the compiler and runtime from allocating volatile variables in registers.

2) not allowing the compiler/optimizer to reorder field access from the code. Effectively, this is like acquiring a lock.

3) Forcing the compiler/runtime to flush a volatile variable to main memory from cache as soon as it is written.

4) Marking a cache as invalidated before a volatile field is read.

From the article:

"Volatile fields are special fields which are used for communicating state between threads. Each read of a volatile will see the last write to that volatile by any thread; in effect, they are designated by the programmer as fields for which it is never acceptable to see a "stale" value as a result of caching or reordering. The compiler and runtime are prohibited from allocating them in registers. They must also ensure that after they are written, they are flushed out of the cache to main memory, so they can immediately become visible to other threads. Similarly, before a volatile field is read, the cache must be invalidated so that the value in main memory, not the local processor cache, is the one seen. There are also additional restrictions on reordering accesses to volatile variables. "

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

于 2014-10-05T17:29:31.270 回答