0
\$\begingroup\$

I came across the following code snippet:

static private volatile ConfigUserCredentails maintenanceUserCred = null;
static private Object maintenanceUserLock = new Object();

/**
 * This method is slower.  Recommend use the one from cache.  
 *
 * @return The username/password credentials of the maintenance user.
 * @throws IOException
 */
public static ConfigUserCredentails getMaintenanceUserCredentials() throws IOException {
    return readCredentialsFromFile(MAINTENANCE_CREDENTIALS_PROPS, Crypt.getDefaultCrypt());
}

/**
 * 
 * @return The username/password credentials of the maintenance user.
 * @throws IOException
 */
public static ConfigUserCredentails getMaintenanceUserCredentialsFromCache() throws IOException {
    if (maintenanceUserCred != null) {
        return maintenanceUserCred;
    }
    synchronized(maintenanceUserLock) {
        if (maintenanceUserCred == null) {
            maintenanceUserCred = getMaintenanceUserCredentials();
        }
    }
    return maintenanceUserCred;
}

'getMaintenanceUserCredentials()' just reads the user credentials from file and creates new user object.

My questions are:

  1. What is the purpose of 'volatile'?
  2. Why would one need the 'synchronized' block?

Thanks, Rafik

\$\endgroup\$
  • 2
    \$\begingroup\$ Hey, welcome to Code Review! Unfortunately your question does not match what this site is about. One of our requirements for questions is: "Authorship of code: Since Code Review is a community where programmers improve their skills through peer review, we require that [...] the poster know why the code is written the way it is." Have a look at our help center for more information. \$\endgroup\$ – Graipher Sep 6 '18 at 8:25
1
\$\begingroup\$
  1. When a variable is volatile, then the code that access that variable is forced to read/write the value of variable from/to the memory. Without volatile, the value of variable can be (temporarily) stored to place (like register/cache) where changes are not immediately visible to other threads, or changes by other threads are not immediately visible.

  2. synchronized is used in the code for avoiding concurrent and duplicate initialization of maintenanceUserCred. Without the synchronized block, two or more threads can enter to maintenanceUserCred = getMaintenanceUserCredentials(); line at the same time. The synchronized will pass only one thread at a time to the block, so maintenanceUserCred = getMaintenanceUserCredentials(); will be done only once.

Both synchronized and volatile will create memory barriers, that ensures that loads and stores are really from/to the main memory (not only local cache of current CPU core).

For example without volatile and synchronized the generated code could effectively work like the following code:

ConfigUserCredentails tmp = maintenanceUserCred;

if (tmp != null) {
    return tmp;
}
tmp = getMaintenanceUserCredentials();
maintenanceUserCred = tmp;
return tmp;

That will allow several threads to call getMaintenanceUserCredentials() at the same time and threads may obtain different ConfigUserCredentails objects.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.