Spliterator

1. 简介

我们常常遍历数组,集合,map等,都是在单线程里面遍历的 ,jdk1.8 之后,出现Spilterator 可以让我们在多线程下遍历集合,基本思想就是把一个集合分割成多个小集合由多个线程遍历

2.接口方法介绍

// 如果有,则遍历下一个元素
tryAdvance
// 遍历 剩余的元素
forEachRemaining
// 就是尝试分割, 分割失败(元素太少,或者已经开始遍历,或者获得分割器x效率低下)返回null ,每次分割一半
trySplit
// 返回估算的大小,如果SIZED 和SUBSIZED 那么返回 大小是确定的
estimateSize
// 就是调用上面的方法, 如果不确定那么返回-1
getExactSizeIfKnown
//这个分割器的特性
characteristics
// 判断此分割器是否含有这个特性 (使用 按位与操作的)
hasCharacteristics
// 获取比较器,如果是自然排序的,返回null, 如果是比较器排序的返回比较器,否则跑出一次
getComparator

3. 分割器的特性介绍

// 指定这个分割器按照顺序取出元素 如数组,List产生的Spiterator都是有这个特性的
ORDERED 
//  不重复  如Set 
DISTINCT
// 排好序的 如 Set
SORTED
// 有固定大小的 ,我们常常使用非多线程安全集合,如Set,List都是,并发的集合在Spilerator分割和遍历的时候是会发生变化的
SIZED
// 里面的元素不是空的
NONNULL
// 集合是不可变的 ,那么也具有 SIZED和SUBSIZED
IMMUTABLE
// 支持并发的 ,那么一般没有SIZED和SUBSIZED 如ConcurrentSkipListSet
CONCURRENT、
// 分割后的子大小也是不变的       
SUBSIZED

注意 : 子Spliterator 与父Spliterator的特性可能不一样

4.子接口介绍

这些子接口使用的是原生类型,执行速度比包装类型快很多

4.1OfPrimitive

 public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
            extends Spliterator<T>
 // T :我们元素的类型
 // T_CONS: 我们forEachRemaining 消费的类型,是IntConsumer或者LongConsumer或者DoubleCosumer中的一个
// T_SPLITR : OfPrimitive子接口的类型
// 其实这个接口就起抽象 原子类型的Spiterator

4.2OfInt

对OfPrimitive的实现 T 用的是Integer ,而且还添加了一个boolean
tryAdvance(IntConsumer action);注意参数是IntConsumer
默认实现了Spilterator的tryAdvance()方法,实现如下

default boolean tryAdvance(Consumer<? super Integer> action) {
            if (action instanceof IntConsumer) {
                return tryAdvance((IntConsumer) action);
            }
            else {
                if (Tripwire.ENABLED)
                    Tripwire.trip(getClass(),
                                  "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
                return tryAdvance((IntConsumer) action::accept);
            }

这个方法的实现很奇怪,奇怪是action 实现了Consumer接口,又实现了IntConsumer,然而Consumer和IntConsumer不是父子关系,其实这个两个接口的lamdab表示式子是相同的

Consumer consumer = System.out::println;
IntConsumer intConsumer = System.out::println;
// 但是这个两个之间是不能相互强转的 ,所以认为是这样的有一个子类实现了着两个接口即可,便可以理解了
 static  class ConsumerImpl implements Consumer<Integer>,IntConsumer{

        @Override
        public void accept(Integer value) {

        }

        @Override
        public void accept(int value) {

        }
    }

4.3 OfLong

跟OfInt一样 ,只不过 T 就是Long ,而 Consumer是就是LongConsumer

4.4OfDouble

跟OfInt一样 ,只不过 T 就是Double,而 Consumer是就是DoubleConsumer

5 Spliterotors介绍

这类和Spliterator 的关系就像 Collections 和Collection的关系,他是Spliterator的伴生对象。作用就是用来创建Spliterator的

// Spliterator.spliterator 方法 有很多重载方法,基于原生类型和引用类型的数组,还有集合的等等
// 如: 从int[]中创建 ,指定特行一般就是 SIZED |SUBSIZE|ORDERED|NONULL
Spliterator.OfInt spliterator(int[] array,  int additionalCharacteristics) 
Spliterator<T> spliterator(Object[] array, int additionalCharacteristics)
spliterator(Collection<? extends T> c,  int characteristics)
//等等。。

6 简单HelloWorld

这个例子是用 Spliterator 和 ForkJoin结合使用的。他们的特性刚刚切合

package liusheng.main.hello;

import java.util.Random;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;

public class SpliteratorHelloWorld {
    public static void main(String[] args) {
        // 我们生成1000个随机数
        Random random = new Random();
        int[] array = IntStream.range(0, 1000).map(i-> random.nextInt(100)).toArray();
        // 创建分割器
        Spliterator.OfInt sumSpliterator = Spliterators.spliterator(array, Spliterator.ORDERED | Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.NONNULL);
        Sum sum = new Sum(sumSpliterator);
        // 因为我们使用的ForkJoinTask ,所以我们要创建 ForkJoinPool
        ForkJoinPool commonPool = ForkJoinPool.commonPool();
        sum  = (Sum) commonPool.submit(sum);

        System.out.println(sum.join());
    }
    /**
     * 因为这里使用是原生类型 ,所以我们使用原生类型Spliterator
     */
    static class Sum extends RecursiveTask<Long> {
        private Spliterator.OfInt spiterator;

        public Sum(Spliterator.OfInt spiterator) {
            this.spiterator = spiterator;
        }

        @Override
        protected Long compute() {
            // 如果是100个以内,直接计算 原生类型的数组的大小是不会发生变化的,所以这个是精确的
            if (spiterator.estimateSize() <= 100) {
                long[] sum = new long[1];
                spiterator.forEachRemaining((IntConsumer) i -> {
                    sum[0] += i;
                });
                return sum[0];
            }
            // 进行分割
            Spliterator.OfInt split = spiterator.trySplit();
            if (split != null) {
                Sum left = new Sum(spiterator);
                Sum right = new Sum(split);
                //计算
                left.fork();
                //计算
                right.fork();
                //等待结果
                return left.join() +
                right.join();

            }
            return 0L;
        }
    }
}

7.深入使用

暂时还没有想到以后再补吧。。。。

8.总结

Spliterator的主要作用就是为了提高遍历速度,当每次分两块大小相等的时候,效率是最高的,但是这是理想情况,有时,当数据结构不理想的时候,或者分割相差太大,那么返回会降低效率。所以我们要在合适的场景下使用。
有什么错误的地方望大佬指正,相互学习嘛。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容