JAVA复制流(Forked streams/ Forking a stream)
来源:互联网 发布:学校机房监控软件 编辑:程序博客网 时间:2024/05/20 16:33
基本的方法是创建一个流并发的执行多个操作效果, 将该方法应用到流中, 并收集结果。每个复制流的结果都封装在 CompletableFuture 的实例中。每次复制都是异步执行的。流到分叉是使用与消费者的 forEach, 推动一个元素到每次操作通过 LinkedBlockingQueue。分叉流的来源是一个特殊的 Spliterator, 涵盖了相关的 LinkedBlockingQueue 元素。
ForkingStreamConsumer同时实现了前面定义的Results接口和Consumer接口。随着我们进一步剖析它的实现细节,你会看到它主要的任务就是处理流中的元素,将它们分发到多个BlockingQueues中处理, BlockingQueues的数量和通过fork方法提交的操作数是一致的。注意,我们很明确地知道流是顺序处理的,不过,如果你在一个并发流上执行forEach方法,它的元素可能就不是顺序地被插入到队列中了。 finish方法会在队列的末尾插入特殊元素表明该队列已经没有更多需要处理的元素了。
这里就不做过多解释说明,还是主要看代码吧。
复制流简单实例:
package stream.fork;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Optional;import java.util.Spliterator;import java.util.concurrent.CompletableFuture;import java.util.concurrent.LinkedBlockingQueue;import java.util.function.Consumer;import java.util.function.Function;import java.util.stream.Collectors;import java.util.stream.IntStream;import java.util.stream.Stream;import java.util.stream.StreamSupport;public class ForkExample { public static void main(String[] args) throws Exception { // Set up the forks StreamForker<String> forker = new StreamForker<>(); StreamForker.Memento<String> mr1 = forker.addFork( s -> s.map(String::toUpperCase).collect(Collectors.joining())); StreamForker.Memento<Integer> mr2 = forker.addFork( s -> s.mapToInt(Integer::valueOf).sum()); StreamForker.Memento<Map<Integer, Long>> mr3 = forker.addFork( s -> s.collect(Collectors.groupingBy(String::length, Collectors.counting()))); StreamForker.Memento<Optional<String>> mr4 = forker.addFork( s -> s.skip(10).findFirst()); // Fork an existing stream 4 times Stream<String> p = IntStream.range(0, 100).mapToObj(Integer::toString); ForkedStreamResults rs = forker.fork(p); // Wait for all forks to complete rs.all().join(); // Get the results of each fork CompletableFuture<String> r1 = rs.get(mr1); CompletableFuture<Integer> r2 = rs.get(mr2); CompletableFuture<Map<Integer, Long>> r3 = rs.get(mr3); CompletableFuture<Optional<String>> r4 = rs.get(mr4); System.out.println(r1.get()); System.out.println(r2.get()); System.out.println(r3.get()); System.out.println(r4.get()); } /** * A forker of streams * * @param <T> the type of elements output from the forked stream. */ public static class StreamForker<T> { /** * A memento to a fork * * @param <R> the type of result of the fork */ static class Memento<R> { } private Map<Memento<?>, Function<Stream<T>, ?>> forks = new HashMap<>(); /** * Add a fork * * @param f the fork function to apply to a forked stream. The stream is * forked, and the function is applied to that forked stream to produce * a result. * @param <R> the type of result of the fork * @return a typed memento associated with the fork that can be used to * obtain the result returned by the fork function */ public <R> Memento<R> addFork(Function<Stream<T>, R> f) { Memento<R> m = new Memento<>(); forks.put(m, f); return m; } /** * Fork a stream * * <p>The stream will be forked N times where N is the number of forks * added. * * @param s the stream to fork * @return the results of forking */ public ForkedStreamResults fork(Stream<T> s) { // @@@ Obtain the spliterator from the stream so as to // get the characteristics that can be passed to the // LinkedBlockingQueueSpliterator, then re-create the // to-be-forked stream from that Spliterator ForkingStreamConsumer<T> consumer = build(); try { // @@@ If the stream is parallel then the encounter order, // if any, will not be preserved, in addition the parallel // execution will compete with the execution of the forked // streams s.sequential().forEach(consumer); } finally { consumer.finish(); } return consumer; } ForkingStreamConsumer<T> build() { List<LinkedBlockingQueue<T>> queues = new ArrayList<>(); Map<Memento<?>, CompletableFuture<?>> actions = new HashMap<>(); for (Map.Entry<Memento<?>, Function<Stream<T>, ?>> e : forks.entrySet()) { LinkedBlockingQueue<T> queue = new LinkedBlockingQueue<>(); queues.add(queue); // Forked representation of the stream Stream<T> source = StreamSupport.stream( new LinkedBlockingQueueSpliterator<>(queue), false); Function<Stream<T>, ?> f = e.getValue(); CompletableFuture<?> action = CompletableFuture.supplyAsync( () -> f.apply(source)); actions.put(e.getKey(), action); } return new ForkingStreamConsumer<>(queues, actions); } } /** * The results of forking a stream */ public static interface ForkedStreamResults { /** * @return a completable future encapsulating the futures of all forks * that is completed when all forks complete. */ public CompletableFuture<Void> all(); /** * Get the completable future encapsulating the result of a fork * @param m the memento associated with the fork * @param <R> the type of results of the fork * @return the completable future encapsulating the result of the fork */ public <R> CompletableFuture<R> get(StreamForker.Memento<R> m); } static class ForkingStreamConsumer<T> implements Consumer<T>, ForkedStreamResults { // Object element marking the end of the stream static final Object SENTINAL = new Object(); private final List<LinkedBlockingQueue<T>> queues; private final Map<StreamForker.Memento<?>, CompletableFuture<?>> actions; ForkingStreamConsumer(List<LinkedBlockingQueue<T>> queues, Map<StreamForker.Memento<?>, CompletableFuture<?>> actions) { this.queues = queues; this.actions = actions; } @Override public void accept(T t) { // @@@ Buffering issues, can barf if queue is full // i.e. producer is faster than consumer queues.forEach(q -> q.add(t)); } @Override public CompletableFuture<Void> all() { return CompletableFuture.allOf( actions.values().stream().toArray(CompletableFuture[]::new)); } @Override @SuppressWarnings("unchecked") public <R> CompletableFuture<R> get(StreamForker.Memento<R> m) { return (CompletableFuture<R>) actions.get(m); } @SuppressWarnings("unchecked") void finish() { accept((T) SENTINAL); } } static class LinkedBlockingQueueSpliterator<T> implements Spliterator<T> { private final LinkedBlockingQueue<T> q; private boolean finished; LinkedBlockingQueueSpliterator(LinkedBlockingQueue<T> q) { this.q = q; } @Override public boolean tryAdvance(Consumer<? super T> action) { if (!finished) { T t; while (true) { try { t = q.take(); break; } catch (InterruptedException e) { } } if (t != ForkingStreamConsumer.SENTINAL) { action.accept(t); return true; } finished = true; } return false; } @Override public Spliterator<T> trySplit() { // @@@ Support limited splitting, using buffering with say // q.drainTo return null; } @Override public long estimateSize() { // @@@ Support size if known by forking stream return 0; } @Override public int characteristics() { // @@@ Inherit characters from forking stream return 0; } }}
阅读全文
0 0
- JAVA复制流(Forked streams/ Forking a stream)
- 【Java Streams 1】介绍java.util.stream
- Oracle 10g 流复制(Streams Replication)配置
- Java Streams,第 1 部分: java.util.stream 库简介
- c2 Streams - Input Stream
- Streams流复制的异常检测
- Streams流复制的异常检测
- Streams流复制的异常检测
- Java 流(Stream)
- Java流(Stream)
- FunDA(9)- Stream Source:reactive data streams
- streams流复制中如何初始化复制对象
- streams流复制中如何初始化复制对象
- Creating a thread VS Forking a thread
- oracle10 单向stream流复制
- Streams复制文档
- streams schema级别复制
- streams table级别复制
- JS一些实用的方法
- javaweb开发中常用的时间工具类
- 防止网页被嵌入iframe广告代码
- Oracle数据移动-不同用户不同表空间之间的数据移动
- Oracle闪回-闪回已经删除的表:
- JAVA复制流(Forked streams/ Forking a stream)
- js原型方式自定义弹窗
- SSM框架使用POI导出EXCEL
- Linux声卡录音程序之——mp3(通过ALSA操作声卡)
- Oracle闪回-闪回错误的DML操作
- js Base64加密
- python3 模块内置变量
- web--鼠标拖拽
- java拼接字符,数据库字符和数字拼接的字符串作为字段,如ID,主键