What is the reason behind “get” method implementat

2019-02-19 08:24发布

问题:

In java an AtomicMarkableReference can be used to update atomically an object reference along with a mark bit.

The javadoc states:

Implementation note: This implementation maintains markable references by creating internal objects representing "boxed" [reference, boolean] pairs.

This is true according to what can be seen in the java 8 source code of the class:

package java.util.concurrent.atomic;

public class AtomicMarkableReference<V> {

    private static class Pair<T> {
        final T reference;
        final boolean mark;
        private Pair(T reference, boolean mark) {
            this.reference = reference;
            this.mark = mark;
        }
        static <T> Pair<T> of(T reference, boolean mark) {
            return new Pair<T>(reference, mark);
        }
    }

    private volatile Pair<V> pair;

    public AtomicMarkableReference(V initialRef, boolean initialMark) {
        pair = Pair.of(initialRef, initialMark);
    }

    // [...] class methods
}

Is there a reason behind the design of the get method of the class?

public V get(boolean[] markHolder) {
    Pair<V> pair = this.pair;
    markHolder[0] = pair.mark;
    return pair.reference;
}

What is the point of using such boolean array (instead of returning the pair of values)? Is a concurrency-driven choice? Or perhaps legacy code?

回答1:

This is because Java has no Pair<L, R> class and probably will not, even despite of the fact that standard library has at least three classes which have private static class Pair. Adding Pair class were discussed by OpenJDK developers more than once and proposal was always rejected. This mail is a very good explanation why pair shouldn't be presented as standard class (also, the whole mail thread is very useful):

The problem is that classes like Pair simply go that much further to indulge the desire to never have to create any actual types of our own. When we're forced to create our own types, we begin to model our data more appropriately, which I believe leads us to create good abstractions at broader levels of granularity as well.

As long as AtomicMarkableReference doesn't expose its Pair class and in Java you can't change value of passed reference (in the way that such change will be observable by caller), the only way to return both reference and bit flag is to return one of them from method and set second into passed as argument array. So it's not about concurrency, neither about legacy, it's about language design decision.