Unstable + immutable object holder = thread safe?

I had an example from the book "java concurrency pratique" that says an unstable and immutable holder object provides thread safety. But I do not understand the example given in 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

  • The volatile keyword ensures that the submitted cache is visible to all threads.

  • The OneValueCache class is immutable. But we can change the link to the variable cache.

But I can not understand why the VolatileCachedFactorizer class is thread safe.

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

This indicates that the code is not thread safe.

Can someone tell me why this piece of code is considered thread safe and why am I mistaken?

+7
source share
4 answers

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

If subsequent execution requests coefficients 67, it will output them from the cache (since the cache is non-zero and contains coefficients for 67). If he asks for factors of another number, he will not get them from the cache, so he will calculate the factors and save them in the cache, hoping that in the next queries the coefficients of the same number will be set.

Nothing guarantees that two threads will not calculate coefficients from the same number. The only guarantee this code offers is that if the cache currently contains factors for the requested number, these cached factors will be returned (not factors for another number or inconsistent data caused by data consumption).

+4
source

There are two attributes in a thread safe operation.

  • Visibility
  • Atomicity

To ensure full flow work, it must satisfy both requirements.

In your example, this is safe for any data race (i.e. visibility) (1), but not atomic (2). Most likely, the author wanted to illustrate that the above code is safe for publication and is ignored to indicate (or perhaps you have not read it) that it is not atomic.

Can someone tell me why this piece of code is considered thread safe and why am I mistaken?

Your inclination is correct here, and your question about the safety of this class is legitimate.

+3
source

It is thread safe in the sense that the cached value is visible to other threads only when OneValueCache is in the correct state. An immutable class ensures that all values โ€‹โ€‹are valid because the class must be created each time the values โ€‹โ€‹change (i.e. you cannot update an already published instance by changing the fields one by one).

However, this does not prevent the simultaneous operation of threads of the same factorization.

+1
source

As far as I know, a parallel problem for this scenario is that factors stored in the cache are not calculated from the corresponding last number stored in the cache. The program initializes a new cache every time after calculating the factors that make it thread safe.

0
source

Source: https://habr.com/ru/post/972701/


All Articles