volatile + immutable holder object = thread safe?
Asked Answered
H

4

8

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 ?

Hermann answered 23/7, 2014 at 12:44 Comment(3)
Note that this is something of a toy case. Most thread safety problems are much more complex.Nape
I was puzzled also.. xD But then I realized that the task is to store only the last factor. Simple as that. Doesn't matter if calculated twice at the same time or whatever...Desilva
I don't understand, why I can't resolve the factor(i) is it java Math function???Chaperone
P
6

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)

Persecution answered 23/7, 2014 at 15:13 Comment(0)
F
3

There are two attributes to a thread-safe operation

  1. Visibility
  2. Atomicity

To have a completely thread-safe operation it needs to satisfy both requirements.

In your example it is safe of any data races (ie Visibility) (1) but is not atomic (2). Chances are, the author wanted to illustrate that the code above is safe for publication and neglected to point out (or maybe you hadn't read) that it was not atomic.

Could anyone tell me why this piece of code is considered as thread safe and why i am wrong ?

Your inclination here is right and your questioning the safety of this class is legitimate.

Faint answered 23/7, 2014 at 15:25 Comment(0)
M
1

It is thread-safe in the sense that the cached value is visible to other threads only when the OneValueCache is in valid state. The immutable class guarantees that all values are valid because the class must be instantiated every time when the values change (i.e. you cannot update already published instance by changing the fields one by one).

However, this does not prevent threads from doing the same factorization work simultaneously.

Microsome answered 23/7, 2014 at 15:18 Comment(0)
C
0

As far as i know, the concurrent problem for this scenario is that the factors holded in cache are not computed from the corresponding lastnumber holded in cache. The program initializes a new cache every time after computing the factors which makes it thread safe.

Colorcast answered 20/1, 2019 at 7:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.