0

In The Java Language Specification, Java SE 9 Edition there is a statement:

The Java programming language allows threads to access shared variables (§17.1). As a rule, to ensure that shared variables are consistently and reliably updated, a thread should ensure that it has exclusive use of such variables by obtaining a lock that, conventionally, enforces mutual exclusion for those shared variables.

The Java programming language provides a second mechanism, volatile fields, that is more convenient than locking for some purposes.

I'm trying to figure out for which purposes using volatile is more convenient than locking?

Community
  • 1
  • 1
Evgeny Mamaev
  • 1,237
  • 1
  • 14
  • 31
  • 1
    I’m pretty sure that just means making a field volatile requires adding a mere nine characters to the code (including the space), while synchronization or Locks requires a few lines. – VGR Oct 13 '17 at 13:54
  • @VGR I agree. Generally speaking the notion is much sorter. But volatile still doesn’t cover some cases. – Evgeny Mamaev Oct 13 '17 at 19:51

4 Answers4

2

I'm trying to figure out for which purposes using volatile is more convenient than locking?

It is a more convenient1 solution in simple cases where the volatile is the sole state that needs to be synchronized, and the operations are intrinsically atomic.

For example:

public class Processor extends Thread {
    private volatile stopped;

    public void run() {
        while (!stopped) {
            // do stuff
        }
    }

    public void stop() {
        stopped = true;
    }
}

public class Test {
    public static void main(String[] args) {
        Processor p = new Processor();
        p.start();
        Thread.sleep(1000);
        p.stop();
    }
}

If you use a regular variable for stopped then you need to use synchronized (or some other form or locking) when reading and writing it ... which is more code and less convenient.

 public class Processor extends Thread {
    private stopped;

    public void run() {
        while (!isStopped()) {
            // do stuff
        }
    }

    public synchronized void stop() {
        stopped = true;
    }

    private synchronized boolean isStopped() {
        return stopped;
    }
}

However, this only works as an alternative to locking in simple cases. If the protected state requires more than atomic reads and atomic writes then it will not work. For example:

public class Counter {
    private volatile int counter;

    public void increment() {
        counter = counter + 1;
    }

    private int get() {
        return counter;
    }
}

The above is NOT thread safe because of the way increment() is implemented. For correct (thread-safe) behavior, increment = increment + 1 needs to be done atomically. A volatile does not provide that guarantee. The memory read and write operations are individually atomic, but they are not atomic as a sequence.

AFAIK, there is no thread-safe way to implement Counter using just volatile variables. You need either locks, or an AtomicInteger (which typically relies on CAS hardware support ...)


1 - More convenient if you just count lines of code. If you also factor in the work that the code author and maintainers expends on reasoning that the solution is correct, I would argue that the "convenience" is largely an illusion.


Volatile is better than locking in which cases?

This is a more difficult question because "better" is a loaded term. But if you mean "more performant", then volatile is generally better in situations where it works:

  • A volatile read or write just results in a memory barrier.
  • A locking operation is typically implemented using a CAS instruction and some code to deal with contention. The CAS introduces a memory barrier.
  • An Atomic type is also typically implemented with a CAS.

This analysis is a bit crude, but the bottom like is that if volatile is powerful to do the job, then it is likely to be more efficient than the alternatives. But there are two caveats:

  • Most operations that involve inter-thread communication or synchronization are too complicated for volatile
  • Under normal circumstances, the performance advantage of volatile is too small to be significant. This changes if there is a contention or synchronization bottleneck.
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

To complete the answer of Stephen C, volatile keyword provide atomic read and write of the shared variable and then does not use any monitor contrary to synchronised blocks, inside the JVM.

So for simple variables that are shared, it should be much more efficient from a performance point of view.

But as already mentionned it work only for simple variable access.

See the doc here

greg
  • 306
  • 1
  • 13
1
  • Why volatile: It involves no context switches, or synchronization overhead. A write always flushes the state to main memory.

  • When volatile: In general for boolean variables and if there are no compound statements. i.e. operations are atomic. i++ is not atomic.

  • Alternatives: Atomic variables that use CAS statements or locking.

Ramandeep Nanda
  • 519
  • 3
  • 9
1

When you have single writer Thread and multiple reader Threads, volatile can be used.

But if you have multiple writer & reader threads, volatile does not provide data consistency.

More details can be read @ Difference between volatile and synchronized in Java

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211