Concurrency item-Thoughts on immutability

Source: Internet
Author: User

This article records the immutability of the policy to ensure concurrency security.

The following is a piece of music. The song name is an unchangeable object ^



Organizes a series of actions into an atomic operation to ensure immutability conditions, or uses a synchronization mechanism to ensure visibility, to prevent reading of invalid data or changing objects to an inconsistent state, these problems are caused by shared variable data.

If we can ensure that the data is not changeable, we naturally don't have to consider these complicated problems.

Immutable objects must be thread-safe.

It is simple and simple. an unchangeable object has only one State and is controlled by the constructor.

Therefore, it is very easy to judge the state of an unchangeable object.

When we share a mutable object, it is unpredictable to change its state, especially when it is passed as a parameter to a method that can be overwritten, even worse, the client code can retain the reference of this object, which means the time for changing the state is equally unpredictable.

Compared with the sharing of mutable objects, the sharing of immutable objects is much simpler, and there is almost no need to consider getting a snapshot.

So now we have a new question: how can we make the status immutable?



The "immutable" statement is not clearly defined either in JLS or elsewhere, but immutable is definitely not as simple as adding a final modifier, for example, the field modified by final references a mutable object, while final only guarantees that the point of reference will not change.

Yes, immutable objects and immutable object references are two different things.



We have three conditions for building an immutable object (although it is a "condition", but it is not so hard, it can be regarded as a suggestion ):

1. After an object is created, its status is not changeable.

2. All fields of the object are final

3. The reference is not escaped during creation, so the object is created correctly.


Here is an example of the above three items:

 public final class ThreeStooges {    private final Set<String> stooges = new HashSet<String>();    public ThreeStooges() {        stooges.add("Moe");        stooges.add("Larry");        stooges.add("Curly");    }    public boolean isStooge(String name) {        return stooges.contains(name);    }    public String getStoogeNames() {        List<String> stooges = new Vector<String>();        stooges.add("Moe");        stooges.add("Larry");        stooges.add("Curly");        return stooges.toString();    }}

Let's check whether three conditions are met:

1. After an object is created, make sure its status is changeable. Does it change? We first modified stooges with private, in the two public methods provided, the first method returns Boolean, and the second method getstoogenames re-creates a stooges and ensures the same logic rather than directly referencing stooges field.

2. All fields of an object are final. Obviously, we use final to describe the object to prevent the object state from changing its reference during the object lifecycle.

3. the reference is not escaped during creation. When stooges declares, we specify the reference and initialize it in the constructor. No external methods can be referenced to this state and adapted.



I have to say that this final modifier is the key.

The most intuitive impression of the final keyword is that if the reference point of an object modified with final is not changed (it is difficult to express it clearly in any way, but you know), but even if you reference a variable instance, you can simplify the process by adding final to the status, it's much easier to analyze the total score of basically immutable objects ....

The final and synchronized keywords also have multiple semantics, that is, they can ensure the security of the initialization process, so that they can be freely shared and do not need to be synchronized (This synchronization process does not include visibility ).



The following is an example of using final (more specifically, it should be immutable) to ensure the atomicity of operations (to ensure variability.

After receiving a parameter, a servlet transmits the parameter to the factor method for calculation and responds to the result.

Assuming that this factor method is very time-consuming, we come up with a method to temporarily alleviate this situation, that is, if the parameters of the next request are the same as those of the previous request, the results in the response cache will be returned.

That is to say, each request requires an additional step, that is, to determine whether the number of the request is the same as that in the cache. If the number is different, re-calculate the request. This segment is not an atomic operation, and issues that may damage the variability conditions.

To solve this problem, we can use synchronized to ensure its atomicity, but here we use another method to use immutable objects:

public class OneValueCache {    private final BigInteger lastNumber;    private final BigInteger[] lastFactors;    public OneValueCache(BigInteger i,                         BigInteger[] factors) {        lastNumber = i;        lastFactors = Arrays.copyOf(factors, factors.length);    }    public BigInteger[] getFactors(BigInteger i) {        if (lastNumber == null || !lastNumber.equals(i))            return null;        else            return Arrays.copyOf(lastFactors, lastFactors.length);    }}

How is this immutable object designed?

First, we ensure that all States are modified with final and initialized in the unique constructor. Note that we use arrays to initialize lastfactors. copyof ensures its correct structure, that is, preventing escape.

Then there is the only public method. This method returns exactly the calculated factors, but we cannot directly return factors. We also use arrays. copyof to prevent escape.



The following is the cache servlet. Only one field of the entire object is the cache. We use volatile to ensure the visibility during concurrency, that is, when thread a changes the reference, thread B can immediately see the new cache.

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);            cache = new OneValueCache(i, factors);        }        encodeIntoResponse(resp, factors);    }    void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) {    }    BigInteger extractFromRequest(ServletRequest req) {        return new BigInteger("7");    }    BigInteger[] factor(BigInteger i) {        return new BigInteger[]{i};    }}



This article is from the "alvez.-99.9% 0b/s" blog, please be sure to keep this source http://alvez.blog.51cto.com/7711135/1549811

Concurrency item-Thoughts on immutability

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.