Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

volatile + immutable holder object = thread safe?

I had an example from the book 'java concurrency pratique', who says that volatile and immutable holder object gives thread safety. But I do not understand the example given by the book.

The code is as follows:

public class VolatileCachedFactorizer extends GenericServlet implements Servlet {

  private volatile OneValueCache cache = new OneValueCache(null, null);

  public void service(ServletRequest req, ServletResponse resp) {
    BigInteger i = extractFromRequest(req);
    BigInteger[] factors = cache.getFactors(i);
    if (factors == null) {             
        factors = factor(i);  //----------> thread A
        cache = new OneValueCache(i, factors);  //---------> thread B
    }
    encodeIntoResponse(resp, factors);
  }   
 }

public class OneValueCache {

  private final BigInteger lastNum;
  private final BigInteger[] lastFactors;

  public OneValueCache(BigInteger i, BigInteger[] lastFactors){
    this.lastNum = i;
    this.lastFactors = lastFactors;
  }

  public BigInteger[] getFactors(BigInteger i){
    if(lastNum == null || !lastNum.equals(i))
        return null;
    else
        return Arrays.copyOf(lastFactors, lastFactors.length);
  }

}

I understand that

  1. The key word volatile assure that the filed cache is visible to all threads.

  2. The class OneValueCache is immutable. But we can change the reference of the variable cache.

But I cannot understand why the class VolatileCachedFactorizer is thread safe.

For two threads (Thread A and Thread B), if thread A and thread B arrive at factors == null at the same time, the two threads A and B will both try to create the OneValueCache. Then Thread A arrives at factors = factor(i) while threadB arrives at cache = new OneValueCache(i, factors) at the same time. Then the thread A will create a OneValueCache which overwrites the value created by threadB (OneValueChange is immutable but the reference to the variable cache can be changed).

It shows that the code is not thread safe.

Could anyone tell me why this piece of code is considered to be thread safe and why I am wrong ?

like image 355
yunshi Avatar asked Jul 23 '14 12:07

yunshi


People also ask

Does immutable objects are thread-safe?

To put it simply, a class instance is immutable when its internal state can't be modified after it has been constructed. A MessageService object is effectively immutable since its state can't change after its construction. So, it's thread-safe.

Is volatile variable thread-safe?

Unlike synchronized methods or blocks, it does not make other threads wait while one thread is working on a critical section. Therefore, the volatile keyword does not provide thread safety when non-atomic operations or composite operations are performed on shared variables.

Can we use immutable objects in multithreading?

So, Immutable objects are always thread-safe, but their references may not be. To make their references thread-safe, we may need to access them from synchronized blocks/methods. @Akki No, ArrayList cannot be considered thread-safe unless we take care of the concurrency manually using things like synchronization.

What is the disadvantage of immutable classes?

The only real disadvantage of immutable classes is that they require a separate object for each distinct value. Creating these objects can be costly, especially if they are large.


1 Answers

So, two threads compute factors (one for 67, and the other for 89), and then store their result into the cache variable. The last thread that sets the variable wins. Let's say the first thread is the last one to store its factors in the cache. The cache thus contains the factors for 67.

If a subsequent execution asks for the factors of 67, it will get them from the cache (because the cache is not null, and contains the factors for 67). If it asks for the factors of another number, it won't get them from the cache, will thus compute the factors, and store them in the cache, hoping that the following requests will ask for the factors of the same number.

Nothing guarantees that two threads won't compute the factors from the same number. The only guarantee that this code offers is that, if the cache currently contains the factors for the requested number, these cached factors will be returned (and not factors for another number, or inconsistent data cause by a data race)

like image 63
JB Nizet Avatar answered Oct 22 '22 08:10

JB Nizet