Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use volatile and synchronized

I know there are many questions about this, but I still don't quite understand. I know what both of these keywords do, but I can't determine which to use in certain scenarios. Here are a couple of examples that I'm trying to determine which is the best to use.

Example 1:

import java.net.ServerSocket;

public class Something extends Thread {

    private ServerSocket serverSocket;

    public void run() {
        while (true) {
            if (serverSocket.isClosed()) {
                ...
            } else { //Should this block use synchronized (serverSocket)?
                //Do stuff with serverSocket
            }
        }
    }

    public ServerSocket getServerSocket() {
        return serverSocket;
    }

}

public class SomethingElse {

    Something something = new Something();

    public void doSomething() {
        something.getServerSocket().close();
    }

}

Example 2:

public class Server {

    private int port;//Should it be volatile or the threads accessing it use synchronized (server)?

    //getPort() and setPort(int) are accessed from multiple threads
    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

}

Any help is greatly appreciated.

like image 753
Stripies Avatar asked Mar 24 '12 10:03

Stripies


People also ask

Do I need to use volatile with synchronized?

You can do synchronization without using synchronized block. It's not a necessary to use volatile variable in it... volatile updates the one variable from main memory..and synchronized Update all shared variables that have been accessed from main memory..

What is the use of volatile and synchronized?

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.

When should volatile be used?

Yes, volatile must be used whenever you want a mutable variable to be accessed by multiple threads. It is not very common usecase because typically you need to perform more than a single atomic operation (e.g. check the variable state before modifying it), in which case you would use a synchronized block instead.

When should a method be synchronized?

Synchronization is needed when Object is mutable. If shared Object is immutable or all the threads which share the same Object are only reading the Object's state not modifying then you don't need to synchronize it. Java programming language provide two synchronization idioms: Methods synchronization.


2 Answers

A simple answer is as follows:

  • synchronized can always be used to give you a thread-safe / correct solution,

  • volatile will probably be faster, but can only be used to give you a thread-safe / correct in limited situations.

If in doubt, use synchronized. Correctness is more important than performance.

Characterizing the situations under which volatile can be used safely involves determining whether each update operation can be performed as a single atomic update to a single volatile variable. If the operation involves accessing other (non-final) state or updating more than one shared variable, it cannot be done safely with just volatile. You also need to remember that:

  • updates to non-volatile long or a double may not be atomic, and
  • Java operators like ++ and += are not atomic.

Terminology: an operation is "atomic" if the operation either happens entirely, or it does not happen at all. The term "indivisible" is a synonym.

When we talk about atomicity, we usually mean atomicity from the perspective of an outside observer; e.g. a different thread to the one that is performing the operation. For instance, ++ is not atomic from the perspective of another thread, because that thread may be able to observe state of the field being incremented in the middle of the operation. Indeed, if the field is a long or a double, it may even be possible to observe a state that is neither the initial state or the final state!

like image 142
Stephen C Avatar answered Oct 17 '22 05:10

Stephen C


The synchronized keyword

synchronized indicates that a variable will be shared among several threads. It's used to ensure consistency by "locking" access to the variable, so that one thread can't modify it while another is using it.

Classic Example: updating a global variable that indicates the current time
The incrementSeconds() function must be able to complete uninterrupted because, as it runs, it creates temporary inconsistencies in the value of the global variable time. Without synchronization, another function might see a time of "12:60:00" or, at the comment marked with >>>, it would see "11:00:00" when the time is really "12:00:00" because the hours haven't incremented yet.

void incrementSeconds() {
  if (++time.seconds > 59) {      // time might be 1:00:60
    time.seconds = 0;             // time is invalid here: minutes are wrong
    if (++time.minutes > 59) {    // time might be 1:60:00
      time.minutes = 0;           // >>> time is invalid here: hours are wrong
      if (++time.hours > 23) {    // time might be 24:00:00
        time.hours = 0;
      }
    }
  }

The volatile keyword

volatile simply tells the compiler not to make assumptions about the constant-ness of a variable, because it may change when the compiler wouldn't normally expect it. For example, the software in a digital thermostat might have a variable that indicates the temperature, and whose value is updated directly by the hardware. It may change in places that a normal variable wouldn't.

If degreesCelsius is not declared to be volatile, the compiler is free to optimize this:

void controlHeater() {
  while ((degreesCelsius * 9.0/5.0 + 32) < COMFY_TEMP_IN_FAHRENHEIT) {
    setHeater(ON);
    sleep(10);
  }
}

into this:

void controlHeater() {
  float tempInFahrenheit = degreesCelsius * 9.0/5.0 + 32;

  while (tempInFahrenheit < COMFY_TEMP_IN_FAHRENHEIT) {
    setHeater(ON);
    sleep(10);
  }
}

By declaring degreesCelsius to be volatile, you're telling the compiler that it has to check its value each time it runs through the loop.

Summary

In short, synchronized lets you control access to a variable, so you can guarantee that updates are atomic (that is, a set of changes will be applied as a unit; no other thread can access the variable when it's half-updated). You can use it to ensure consistency of your data. On the other hand, volatile is an admission that the contents of a variable are beyond your control, so the code must assume it can change at any time.

like image 23
Adam Liss Avatar answered Oct 17 '22 06:10

Adam Liss