views:

1041

answers:

6

Possibly similar question:

http://stackoverflow.com/questions/106591/


Today I was debugging my game; It had a very difficult threading problem that would show up every few minutes, but was difficult to reproduce. So first I added the synchronized keyword to each of my methods. That didn't work. Then I added the volatile keyword to every field. The problem seemed to just fix itself.

After some experimentation I found that the field responsible was a GameState object which kept track of my game's current state, which can be either playing or busy. When busy, the game ignores user input. What I had was a thread that constantly changed the state variable, while the Event thread reads the state variable. However, after one thread changes the variable, it takes several seconds for the other thread to recognize the changes, which ultimately causes the problem.

It was fixed by making the state variable volatile.

Why aren't variables in Java volatile by default and what's a reason not to use the volatile keyword?

+5  A: 

Because the compiler can't optimise volatile variables.

volatile tells the compiler that the variable can change at any time. Therefore, it can't assume that the variable won't change and optimise accordingly.

David Johnstone
+14  A: 

To make a long story short, volatile variables--be they in Java or C#--are never cached locally within the thread. This doesn't have much of an implication unless you're dealing with a multiprocessor/multicore CPU with threads executing on different cores, as they'd be looking at the same cache. When you declare a variable as volatile, all reads and writes come straight from and go straight to the actual main memory location; there's no cache involved. This has implications when it comes to optimization, and to do so unnecessarily (when most variables don't need to be volatile) would be inflicting a performance penalty (paltry as it may or may not be) for a relatively small gain.

Adam Robinson
Even with a single core processor, the compiler ( including the JIT compiler ) may decide to optimize out access to the variable.
Chris Arguin
@Chris: I come from a .NET background, so Java may be different, but I wouldn't think that an instance variable could be optimized away unless it detected that it was never used, and local variables can't be declared volatile (wouldn't really need that), right?
Adam Robinson
@Adam: It can't totally optimise it out. However, something like "y = x * x" may only go to memory to get the value of x once, instead of twice. That's a trivial example... now imagine that x is spread out throughout some loop and checked several times. If the compiler never sees you change the value of x, it might decide to read it once and keep it around locally.
Chris Arguin
+2  A: 

Declaring variables volatile generally has a huge impact on performance. On traditional single-threaded systems, it was relativly easy to know what needed to be volatile; it was those things that accessed hardware.

On multi-threaded it can be a little more complex, but I would generally encourage using notifications and event queues to handle passing data between theads in leau of magic variables. In Java it may not matter much; in C/C++ you would get into trouble when those variables cannot be set atomically by the underlying hardware.

Chris Arguin
I'm curious, my only experience with volatile variables is specifically for multithreaded access. What would be the reasoning behind volatile variables in a single-threaded environment?
Adam Robinson
@Adam: In Java and C#, I'm not so sure, although I think JNI might let you play some games. In a C/C++ environment, volatile was critical to indicate that this memory may be changed from somewhere else besides the running program, i.e., hardware that is mapped to that memory location. Since Java and C# don't generally run that close to the hardware, it may be a different game.
Chris Arguin
+6  A: 

While others are correct in pointing out why it would be a bad idea to default to volatile, there's another point to make: there is very likely a bug in your code. Variables seldom need to made volatile: there is always a way to properly synchronize access to variables (either by synchronized keyword, or using AtomicXxx objects from java.util.concurrency): exceptions would include JNI code manipulating these (which is not bound by synchronization directives).

So instead of adding volatile, you may want to figure out WHY it resolved the problem. It isn't the only way to solve it, and there is probably a better way.

StaxMan
While this may or may not be true, it's entirely possible that he's trying to write lock-free code. It's not always necessary to obtain an exclusive lock or use a semaphore if all you're doing is reading. Just my .02
Adam Robinson
True, it is possible, and volatiles are one way. But overhead of volatile (due to reasons others point out) can exceed that of explicit syncing, and unlikely to be lower. Especially given how optimized j.u.concurrent impls are, or even plain old sync.
StaxMan
+5  A: 

Volatiles are really only needed when you're trying to write low-level thread-safe, lock-free code. Most of your code probably shouldn't be either thread-safe or lock-free. In my experience, lock-free programming is only worth attempting after you've found that the simpler version which does do locking is incurring a significant performance hit due to the locking.

The more pleasant alternative is to use other building blocks in java.util.concurrent, some of which are lock-free but don't mess with your head quite as much as trying to do it all yourself at a low level.

Volatility has its own performance costs, and there's no reason why most code should incur those costs.

Jon Skeet
+3  A: 

Personally I think fields should have been final by default and mutable only with an extra keyword, but that boat has sailed along time ago. ;)

Peter Lawrey