Java concurrent Programming-some thoughts on invariance

Source: Internet
Author: User

This article records the policy of ensuring concurrency security--invariance.

(Note: It is immutable, not invariant!)

Organizing a sequence of behaviors into an atomic operation to guarantee invariance conditions, or using a synchronization mechanism to guarantee visibility, to prevent reading of invalid data or objects from becoming inconsistent, is due to the sharing of mutable data.

If we can guarantee that the data is immutable, then these complex problems will naturally not be considered.

Immutable objects must be thread-safe.

It is easy to say that immutable objects have only one state and are controlled by the constructor.

Therefore, it is particularly easy to judge the state of immutable objects.

When we share a mutable object whose state changes behavior is unpredictable, especially when passed as a parameter to the overridden method, it is even worse that the client code can keep a reference to the object, which means that the timing of the change of state is equally unpredictable.

The sharing of immutable objects is much simpler than sharing with mutable objects, and almost no need to take a snapshot.

So now we have a new question: How to make the State immutable?

There is no definite definition of "immutable", either JLS or anywhere, but immutable is not only as simple as adding a final modifier, such as the final modified field refers to a Mutable object, and final guarantees that the reference point is not changed.

Yes, immutable objects and immutable object references are not the same thing.

For how to build an immutable object, we have three conditions (although "conditional", but not so hard, which can be considered a suggestion):

1. Guaranteed state is not variable after object creation

2. All field of the object is final

3. The creation period does not escape its own reference, ensuring that the object is created correctly.

For the above three, give an example here:

123456789101112131415161718192021  publicfinalclassThreeStooges {    privatefinalSet<String> stooges = newHashSet<String>();    publicThreeStooges() {        stooges.add("Moe");        stooges.add("Larry");        stooges.add("Curly");    }    publicbooleanisStooge(String name) {        return stooges.contains(name);    }    publicString getStoogeNames() {        List<String> stooges = newVector<String>();        stooges.add("Moe");        stooges.add("Larry");        stooges.add("Curly");        returnstooges.toString();    }}

Let's check to see if three conditions are met:

1. Is the guaranteed state immutable after the object is created, and does it change? We first modified the Stooges with private, and then the first method in the two public methods provided was to return a Boolean and the second method Getstoogenames we re-created a stooges and guaranteed the same logic instead of a direct reference stooges Field

2. All field of the object is final, and it is clear that we use final to describe to prevent the object state from changing its references during the object life cycle.

3. There is no escaping self-reference during creation, and when the Stooges declaration we specify a reference and initialize it in the constructor, there is no foreign method that can reference the State and adapt it.

I have to say this final modification is the key.

Often our most intuitive impression of the final keyword is that if a final-modified object references a pointer that doesn't change (it's hard to say what it says, but you know it), but even if you reference a mutable instance, it can be simpler to judge the state by adding final, It's much easier to analyze a fundamentally immutable object than to analyze a completely mutable object ....

The final and synchronized keywords also have multiple semantics, that is, to ensure the security of the initialization process so that it can be freely shared without the need for synchronous processing (this synchronization does not include visibility).

The following is an example of a section with final (or, more specifically, immutability) guarantees of operational atomicity (with guaranteed variability).

After a servlet receives the parameter, it evaluates the parameter into the factor method and responds to the result.

Assuming this factor method is time-consuming, we come up with a way to mitigate this situation temporarily, that is, the parameters of the next request and the parameters of the last request respond to the results in the cache.

In other words, we have one more step in each request, that is, we need to determine whether the requested number is the same as in the cache, if the difference is recalculated, and this section is not an atomic operation, the concurrency occurs when there will be a breach of the condition of the variability.

In order to deal with this problem, we can use synchronized to guarantee its atomicity, but here's another way to use immutable objects:

1234567891011121314151617 publicclassOneValueCache {    privatefinalBigInteger lastNumber;    privatefinal BigInteger[] lastFactors;    publicOneValueCache(BigInteger i,                         BigInteger[] factors) {        lastNumber = i;        lastFactors = Arrays.copyOf(factors, factors.length);    }    publicBigInteger[] getFactors(BigInteger i) {        if(lastNumber == null|| !lastNumber.equals(i))            returnnull;        else            returnArrays.copyOf(lastFactors, lastFactors.length);    }}

How is this immutable object designed?

First we guarantee that all States are decorated with final and initialized in a unique constructor, note that the section in the constructor that initializes the lastfactors, we use arrays.copyof to ensure that it is properly constructed, that is, to prevent escaping.

And then the only public method that this method is going to return is the factors we calculated, but we can't go directly back to factors, but also to prevent escaping, we use arrays.copyof.

Here is the servlet using the cache, the entire object has only one field is the cache, we use the volatile modifier to ensure the concurrency of the visibility, that is, thread a changed the reference when thread B can immediately see the new cache.

123456789101112131415161718192021222324 publicclassVolatileCachedFactorizer extendsGenericServlet implementsServlet {    privatevolatileOneValueCache cache = newOneValueCache(nullnull);    publicvoidservice(ServletRequest req, ServletResponse resp) {        BigInteger i = extractFromRequest(req);        BigInteger[] factors = cache.getFactors(i);        if(factors == null) {            factors = factor(i);            cache = newOneValueCache(i, factors);        }        encodeIntoResponse(resp, factors);    }    voidencodeIntoResponse(ServletResponse resp, BigInteger[] factors) {    }    BigInteger extractFromRequest(ServletRequest req) {        returnnewBigInteger("7");    }    BigInteger[] factor(BigInteger i) {        return newBigInteger[]{i};    }}

 

Java concurrent Programming-some thoughts on invariance

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.