JAVA8 Spliterator 并行迭代器用法以及 自定义Spliterator (二)

简介: JAVA8 Spliterator 并行迭代器用法以及 自定义Spliterator (二)

紧接上文《JAVA8 Spliterator 并行迭代器用法以及 自定义Spliterator (一)》


上文实现了demo 说明迭代器一般的切割规律,本文主要介绍如何实现自定义spliterator 以及根据自定义迭代器说明各个方法的作用,本文主要实现了一个简化自定义迭代器MySpliterator 功能简单,主要是为了说明,大家个根据自己业务需求开发


MySpliterator 功能:


1.仅可且只能进行两次分割,超过两次就不允许分割(实际情况肯定不肯是这样,需要根据总数进行切割次数计算,但建议先计算出线程数然后再计算切割次数)


2.输出遍历数据以便查看情况


闲话不多说,上代码

/**
     * @desc: 自定义Spliterator ,只能进行一次切割,然后输出遍历元素
     */
    class MySpliterator implements Spliterator {
        private int[] array;
        private int origin;
        private int fence;
        private boolean canSplit = true;
        private String threadName;
        private MySpliterator(int[] array, String threadName) {
            this.origin = 0;
            this.array = array;
            this.fence = array.length;
            this.threadName = threadName;
        }
        private MySpliterator(int[] array, boolean canSplit, String threadName) {
            this.origin = 0;
            this.array = array;
            this.fence = array.length - 1;
            this.canSplit = canSplit;
            this.threadName = threadName;
        }
        /**
         * @desc: 处理具体某元素,如果成功则数据角标+1并返回true,失败则返回false,相当于iterator hasNext和next一体了
         */
        @Override
        public boolean tryAdvance(Consumer action) {
            if (origin <= fence) {
                int x = array[origin++];
                action.accept(x);
                System.out.println(threadName + ":" + x);
                return true;
            } else
                return false;
        }
        /**
         * @desc: 切割数据为一半一半,如果切割过一次则canSplit变为false,下次再切割则返回null
         */
        @Override
        public Spliterator trySplit() {
            //计算中间值
            int mid = ((origin + fence) >>> 1) & ~1;
            fence = mid;
            System.out.println("进行一次切割");
            return new MySpliterator(Arrays.copyOfRange(array, mid + 1, array.length), false, "线程2");
        }
        /**
         * @desc: 剩余数量,用于评估是否调用切割功能,如果返回<=0则无法切割,将不会调用trySplit
         */
        @Override
        public long estimateSize() {
            if (canSplit) {
                canSplit = false;
                return (fence - origin) / 2;
            } else {
                return 0;
            }
        }
         /**
         * CONCURRENT 特征值表示可以通过多个线程安全同时修改元素源(允许添加,替换和/或删除),而无需外部同步。
         * DISTINCT 特性值这标志着,对于每对遇到的元件 x, y , !x.equals(y) 。
         * IMMUTABLE 特征值表示元素源不能在结构上进行修改; 也就是说,不能添加,替换或删除元素,因此在遍历过程中不会发生这种更改。
         * NONNULL 特征值表示源保证遇到的元素不会为 null
         * ORDERED 特征值表示为元素定义遇到顺序
         * SIZED 表示在遍历或 estimateSize()之前从 estimateSize()返回的值的特征值表示在没有结构源修改的情况下表示完全遍历将遇到的元素数量的精确计数的有限大小。
         * SORTED 特征值表示遇到的顺序遵循定义的排序顺序。
         * SUBSIZED 特征值这标志着从产生的所有Spliterators trySplit()将是既 SIZED和 SUBSIZED
         */
        @Override
        public int characteristics() {
            return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
        }
    }
 @Test
    public void streamMySpliteratorTest() {
        int[] array = IntStream.range(0, 100).toArray();
        MySpliterator mySpliterator = new MySpliterator(array, "线程1");
        Stream<Integer> stream = StreamSupport.stream(mySpliterator, true);
        List<Integer> integers =  stream.map(x -> x+1).collect(Collectors.toList());
        Assert.assertEquals(integers.size(),100);
    }

输出

进行一次切割
线程1:0
线程1:1
线程1:2
线程1:3
线程1:4
线程1:5
线程1:6
线程1:7
线程1:8
线程1:9
线程1:10
线程1:11
线程1:12
线程1:13
线程1:14
线程1:15
线程1:16
线程1:17
线程1:18
线程1:19
线程2:51
线程1:20
线程1:21
线程1:22
线程1:23
线程1:24
线程1:25
线程1:26
线程1:27
线程1:28
线程1:29
线程1:30
线程1:31
线程1:32
线程1:33
线程1:34
线程2:52
线程1:35
线程1:36
线程2:53
线程2:54
线程2:55
线程2:56
线程2:57
线程2:58
线程2:59
线程2:60
线程2:61
线程2:62
线程2:63
线程2:64
线程1:37
线程2:65
线程2:66
线程2:67
线程2:68
线程2:69
线程2:70
线程2:71
线程2:72
线程2:73
线程2:74
线程2:75
线程2:76
线程2:77
线程2:78
线程2:79
线程2:80
线程2:81
线程2:82
线程2:83
线程2:84
线程2:85
线程2:86
线程2:87
线程2:88
线程2:89
线程2:90
线程2:91
线程2:92
线程2:93
线程2:94
线程2:95
线程1:38
线程1:39
线程1:40
线程1:41
线程1:42
线程1:43
线程1:44
线程1:45
线程1:46
线程1:47
线程1:48
线程1:49
线程1:50
线程2:96
线程2:97
线程2:98
线程2:99

看到结果确实是只切割了一次,并且是平均切割,何时启动触发的

tryAdvance 呢,是在启动遍历的时候或者统计的时候比如

1.png

在调用这个时候就会开始启动遍历,然后map的consumer 会映射到到spliterator的tryadance

如下

1.png

1.png

相关文章
|
22天前
|
Java
Java中的抽象类:深入了解抽象类的概念和用法
Java中的抽象类是一种不能实例化的特殊类,常作为其他类的父类模板,定义子类行为和属性。抽象类包含抽象方法(无实现)和非抽象方法。定义抽象类用`abstract`关键字,子类继承并实现抽象方法。抽象类适用于定义通用模板、复用代码和强制子类实现特定方法。优点是提供抽象模板和代码复用,缺点是限制继承灵活性和增加类复杂性。与接口相比,抽象类可包含成员变量和单继承。使用时注意设计合理的抽象类结构,谨慎使用抽象方法,并遵循命名规范。抽象类是提高代码质量的重要工具。
36 1
|
2月前
|
前端开发 Java
java中的Queue队列的用法
java中的Queue队列的用法
19 1
|
2月前
|
XML Java 编译器
java aspectjrt AOP 用法
java aspectjrt AOP 用法
22 0
|
2月前
|
Java Spring 容器
【Java】Spring如何扫描自定义的注解?
【Java】Spring如何扫描自定义的注解?
36 0
|
1天前
|
Java
java lambda 表达式中的双冒号和箭头的用法
java lambda 表达式中的双冒号和箭头的用法
|
1天前
|
Java
java中break和continue的用法例子
java中break和continue的用法例子
|
1天前
|
Java
Java中return的两种用法
Java中return的两种用法
|
1天前
|
算法 安全 Java
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
【4月更文挑战第28天】性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
10 0
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
|
2天前
|
Java API 开发者
Java8并行流——Spliterator
Java8并行流——Spliterator
9 1