Java foundation to improve the Spliterator

        Benpian Java-based foundation The second increase in the previous rapid failure mechanisms we introduce a set of classes java, in fact, the one and this one is for our review after laying the foundation collection classes. We have achieved spliterator () method of this interface Collection in Java8 collection class, and this method is a method inherited Collection Iterable interface available. So in order to later collections of source code review, we look at this Spliterator.

        In this article we explain Spliterator the main interface and use.

Overview

Described above is the source of this class, an object class is used to traverse the data source is cut. The data source can be an array, implement Collection classes, the IO channel or generator function. For the source of the comment that we do not every one of them posted here, and here we talk about the direct source of interpretation of this interface.

  1. Spliterator can either use a tryAdvance () traversal of the elements may be independently according forEachRemaining () to traverse the volume elements

  2. A Spliterator by trySplit some of his elements secede As another Spliterator, possible to do parallel operation. However, the use of an integral, highly unbalanced or inefficient Spliterator less likely to benefit from parallel operation.

  3. Spliterator contains a feature set, the elements of this collection are the following features: ORDERED, DISTINCT, SORTED, SIZED , NONNULL, IMMUTABLE, CONCURRENT, SUBSIZED. Spliterator may be used to control them, or specify simplified calculation. The meaning of these words represent can also be seen in his literally. For example, one generated from the Collection spliterator be labeled SIZED representatives are bounded , a Spliterator generated from the Set will be marked as DISTINCT and represents the elements will not be repeated . If it is generated from the Spliterator SortedSet it will be marked as the representative SORTED elements are classified according to certain rules. Some feature limits the amount of extra method of behavior. For example, if Spliterator is marked ORDERED, both orderly , then the traversal methods must comply with the order of their record. The future may define new feature quantity, so it should not be assigned a new feature to the amount not been traversed elements.

  4. And a Spliterator IMMUTABLE not marked (invariable) or the CONCURRENT (synchronous) policy should have the following contents: when Spliterator bound data source, and detects the data structure of the source of interference occurs after binding, in a first pass, the first division or the first good estimate of the size of Spliterator late-bound data source elements was bound data source (late-bingding) of Spliterator than to create a bound data source. Non-late-bound Spliterator if you bind a data source after the constructor or call any method, bindings Before Spliterator will react when traversing the changes to the data source. After binding, if interference is detected in a structure Spliterator should do our best to throw ConcurrentModificationException an exception, this approach is also called rapid failure (fail-fast our last article was introduced). Batch traversal methods forEachRemaing () can be optimized traversal traverse all the elements after checking interference structure, rather than the structure of the interference checking each element and fail immediately.

  5. Spliterator provides a estimateSize () method to estimate the number of elements was born. Equal to the number of all the elements characteristic amount SIZED as mentioned, this method returns the value of the success encountered convenient ideally. However, even if this value is not correct, the estimated value is also useful for operations performed on the source. For example, it can help determine whether or order further divided traverse the remaining elements.

  6. Despite their obvious utility in parallel algorithms, but Spliterator not thread-safe, on the contrary, the use of Spliterator parallel algorithm should ensure Spliterator once used only by a thread. It is usually easy to achieve through the serial thread limit. A thread calls trySplit () may result in the return of Spliterator be handed over to another thread, that thread in this Spliterator may be traversed may also be divided. If two or more threads operate on the same Spliterator is traversed or division's performance is uncertain. If a source to a Spliterator thread to another thread to handle, it is best to use before the handover tryAdvance () to complete elements of consumption, as certain guarantees (such as estimateSize () the accuracy of the SIZED marked spliterator's) only in effect until traversal begins.

  7. Spliterator original subclass is OfInt, OfLong, OfDouble to provide, subclasses default implementation tyrAdvance (java.util.function.Consumer) and forEachRemaining (java.util.funcion.Consumer) encapsulating the original value corresponding to the type of packaging. Such packing procedure can destroy any performance benefits brought by the original data type, in order to avoid packing, use the corresponding original type of method. For example, Spliterator.OfInt # tryAdvance (java.util.function.IntConsumer) and Spliterator.OfInt # forEachRemaining (java.util.function.IntConsumer) should take precedence over Spliterator.OfInt # tryAdvance (java.util.function.Consumer) and Spliterator .OfInt # forEachRemaining (java.util.function.Consumer). use

  8. Traversing a primitive type sealing method using tryAdvance tryAdvance based ()} and forEachRemaining (java.util.function.Consumer) forEachRemaining () does not affect the original value of the order to the packaging encountered value.

  9. Spliterators like Iterator is to traverse the elements of the data source. Spliterator parallel interface is designed to support efficient inter traversal order traversal outer iterative decomposition of a single support element. In addition, access to the elements of the agreement by Spliterator aimed at achieving a smaller than Iterator single-element overhead and avoid involving hasNext () method inherent competition with next ().

  10. Variable data source, if the time data source Spliterator bound to its data source and between the traverse end receive interference structure (element is added, deleted or replaced) and then any non-deterministic behavior can occur for. For example, such interference can cause any time, when the result of the determination of non-use java.util.stream frame.

  11. A source of interference data structure can be managed by the following ways:

    1. Interference source can not be received in the structure: java.util.current.CopyOnWriteArrayList such a source is an immutable. Created from this source is Sqliterator feature amount IMMUTABLE subscripts represent immutable
    2. It can be synchronous Review: e.g. java.util.concurrent.ConcurrentHashMap The key set is a synchronization source. Created from this source is Spliterator feature amount can CONCURRENT numerals synchronous modification.
    3. Variable source provides late binding and rapid failure mechanisms Spliterator: late binding interference structure can reduce the time of calculation, fast failure detection mechanism detects the start traversing the structure after the occurrence of interference do our best to throw a ConcurrentModificationException. Such as ArrayList and many non-synchronous JDK classes (Collection) provides fast failure and late binding mechanism Spliterator
    4. Variable source to provide a non-binding late but fast failure mechanisms Spliterator: But as it is not late binding source, the source structure is subjected to interference which may affect the time Spliterator span larger.
    5. Variable source provides a late-binding but there is no fail-fast mechanism Spliterator: After traversing the beginning, because there is no interference is detected, this source will exhibit arbitrary, non-deterministic behavior of the line.
    6. The source provides a variable is neither fast nor failure late binding mechanism Spliterator: source adds arbitrary, non-deterministic-risk sexual behavior, because undetected interference may occur after construction.

Detailed methods

Spliterator contains a look at a few main methods:

  1. tryAdvance Boolean (Consumer <Super T?> Action); . If the next element is present, this is performed on the elements and the presence of the given returns true, action, false otherwise If the ORDERED Spliterator is marked, then the sequence will be used given the action to the next element. The Consumer is the concept of java8, that is the function interface, can use their own Baidu, in fact, do not think too much, this is equivalent to the passed method. The latter example we will use. It may be to understand from the following examples.

  2. void forEachRemaining (Consumer <? super T > action); this is Spliterator in a batch operation. He is long in the source code like this:

This approach will rest each element to perform a given operation, the order of execution in the current thread until all elements are processed or throw an error in this action. If Spliterator is marked ORDERED, action performed in the order encountered. action thrown in error will be relayed to the caller. The default implementation of this method is to call tryAdvance () method until this method returns false. It should cover as much as possible.

  1. Spliterator trySplit ();

    If the source Spliterator be divided, then return to a Spliterator, this Spliterator the elements should be split from the source Spliterator out, two Spliterator the elements should not intersect. If Spliterator is marked ORDERED, then returned Splitertor element should be in the front portion of the total elements. Unless Spliterator there are countless elements, then repeated calls trySplit () finally will return null. If it is not null, then it is:

    1. After the pre-division estimateSize () return value must be greater than or equal to split the Spliterator call estimateSize () return value, but also greater than that Spliterator equal return calls estimateSize () return value.

    2. If this Spliterator is marked as SUBSIZED, then this Splitertor call estimateSize before the split () must be equal to the value returned after splitting the Splitertor and that Splitertor return calls estimateSize () values.

    3. This method may return null in some circumstances, including element is empty and can not be divided after the traversal starts, data structures, constraints and efficiency considerations.

    4. Ideally, this method is divided into two elements in order to achieve accurate balanced parallel computing, but deviates from this ideal in many cases is very effective. E.g. substantially divided approximately balanced tree or leaf node may contain one or two elements, the tree can not be further divided. Although similar to that in the above case, the efficiency is good, but the balance is too low and / or too low will generally lower the efficiency of parallel performance trySplit () appears.

  2. long estimateSize();

    1. When returning to the calling forEachRemaining (), count about the number of elements you might encounter. If you calculate the cost or return LONG.MAX_VALUE infinite, unknown or too expensive.

    2. If the number is marked SIZED Spliterator and has not been traversed or separated, or Spliterator marked as SUBSIZED and has not been part of the traverse, then the return value should be an accurate figure describes the elements of a complete traversal of encounter . Otherwise, this could be any number of inaccurate, but will reduce when called trySplit () method.

    3. Even inaccurate estimates are often helpful and computing cost. For example, approximately balanced binary tree splitting may return a value that is half of the estimated number of elements of the parent element; Spliterator root if no accurate count remains, it can be estimated to correspond to the size of its maximum depth 2 power.

  3. int characteristics();

    This returns a feature set Spliterator and his primary colors. You can view the source code specific features to match.

The sample code

This code is an example of source code Spliterator:

package com.lichaobao.collectionsown.spliterators;

import java.util.Objects;
import java.util.Spliterator;
import java.util.concurrent.CountedCompleter;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Consumer;

/**
 * @author lichaobao
 * @date 2019/5/20
 * @QQ 1527563274
 */
public class SourceExmple {
    public static void main(String[] args){
        Object[] a = new  Object[] {1,2,3,4,5,6,7,8,9};
        Object[] tag = new Object[]{"a","b","c","d","e","f","g","h","i"};
        TaggedArray taggedArray = new TaggedArray(a,tag);
        parEach(taggedArray,value ->{
            System.out.print(value+",");
        });
    }
    static <T> void parEach(TaggedArray<T> a,Consumer<T> action){
        Spliterator<T> s = a.spliterator();
        long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
        new ParEach(null, s, action, targetBatchSize).invoke();
    }
    static class ParEach<T> extends CountedCompleter<Void>{
       final Spliterator<T> spliterator;
       final Consumer<T> action;
       final long targetBatchSize;
       ParEach(ParEach<T> parent,Spliterator<T> spliterator,Consumer<T> action,long targetBatchSize){
             super(parent);
             this.spliterator = spliterator; this.action = action;
             this.targetBatchSize = targetBatchSize;
       }
        @Override
        public void compute() {
             Spliterator<T> sub;
             while (spliterator.estimateSize() > targetBatchSize &&
                    (sub = spliterator.trySplit()) != null) {
               addToPendingCount(1);
               new ParEach<>(this, sub, action, targetBatchSize).fork();
             }
             spliterator.forEachRemaining(action);
             propagateCompletion();
        }
    }
}
class TaggedArray<T>{
    private final Object[] elements;
    TaggedArray(T[] data,Object[] tags){
        int size = data.length;
        if(tags.length!=size) throw new IllegalArgumentException();
        this.elements = new Object[2*size];
        for(int i =0,j=0;i<size;++i){
            elements[j++] = data[i];
            elements[j++] = tags[i];
        }
    }
    public Spliterator<T> spliterator(){
        return new TaggedArraySpliterator<>(elements,0,elements.length);
    }
    static class TaggedArraySpliterator<T> implements Spliterator<T>{
        private final Object[] array;
        private int origin;
        private final int fence;

        public TaggedArraySpliterator(Object[] array, int origin, int fence) {
            this.array = array;
            this.origin = origin;
            this.fence = fence;
        }

        @Override
        public void forEachRemaining(Consumer<? super T> action) {
            for (; origin < fence; origin += 2)
                action.accept((T) array[origin]);
        }

        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            if(origin <fence){
                action.accept((T)array[origin]);
                origin+=2;
                return true;
            }else
                return false;
        }

        @Override
        public Spliterator<T> trySplit() {
             int lo = origin; // divide range in half
             int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even
             if (lo < mid) { // split out left half
                origin = mid; // reset this Spliterator's origin
                return new TaggedArraySpliterator<>(array, lo, mid);
             }else       // too small to split
                return null;
        }
        @Override
        public long estimateSize() {
            return (long)((fence-origin)/2);
        }

        @Override
        public int characteristics() {
            return ORDERED|SIZED|IMMUTABLE|SUBSIZED;
        }
    }
}


复制代码

Results are as follows:

Reproduced in: https: //juejin.im/post/5cf2622de51d4550bf1ae7ff

Guess you like

Origin blog.csdn.net/weixin_34146986/article/details/91468579