Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何处理Java8并行流中的状态变量?_Java_Java 8_Reactive Programming - Fatal编程技术网

如何处理Java8并行流中的状态变量?

如何处理Java8并行流中的状态变量?,java,java-8,reactive-programming,Java,Java 8,Reactive Programming,我们正在使用Java8流中的操作链处理事件流。作为处理的一部分,我们希望跟踪事件的计数及其状态,以便进行测试和监视。下面是我们的用例的简化示例,它为给定的日期流打印星期几 public class StreamStateHandling { private static enum Status {RECEIVED, SUCCESS, ERROR}; private Map<Status,Integer> results = new EnumMap<>(St

我们正在使用Java8流中的操作链处理事件流。作为处理的一部分,我们希望跟踪事件的计数及其状态,以便进行测试和监视。下面是我们的用例的简化示例,它为给定的日期流打印星期几

public class StreamStateHandling {

   private static enum Status {RECEIVED, SUCCESS, ERROR};

   private Map<Status,Integer> results = new EnumMap<>(Status.class);

   private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");


   private static Optional<LocalDate> parseDate(String dateString){
    LocalDate localDate = null;
    try {
        localDate = LocalDate.from(formatter.parse(dateString));
    }catch (DateTimeParseException e){
        return Optional.empty();
    }
    return Optional.of(localDate);
   }

   private void doWork(){
    Stream.of("12/31/2014",
            "01-01-2015",
            "12/31/2015",
            "not a date",
            "01/01/2016")
            //.parallel()
            .peek(v -> addResult(Status.RECEIVED))
            .map(StreamStateHandling::parseDate)
            .peek(v -> {if (!v.isPresent()) addResult(Status.ERROR);})
            .filter(Optional::isPresent) 
            .map(Optional::get)
            .map(DayOfWeek::from) 
            .peek(v -> addResult(Status.SUCCESS))
            .forEach(System.out::println); 

       System.out.println(results);
  }
  public static void main(String args[]) {
    new StreamStateHandling().doWork();
  }

  private void addResult(Status status){

    int current = results.getOrDefault(status, 0);
    results.put(status, current + 1);
  }
}
公共类StreamStateHandling{
私有静态枚举状态{已接收,成功,错误};
私有映射结果=新的EnumMap(Status.class);
私有静态最终DateTimeFormatter格式化程序=模式的DateTimeFormatter.of(“MM/dd/yyyy”);
私有静态可选parseDate(字符串dateString){
LocalDate LocalDate=null;
试一试{
localDate=localDate.from(formatter.parse(dateString));
}捕获(DateTimeParse异常){
返回可选的.empty();
}
返回可选的.of(localDate);
}
私房{
2014年12月31日,
"01-01-2015",
"12/31/2015",
“不是约会”,
"01/01/2016")
//.parallel()
.peek(v->addResult(Status.RECEIVED))
.map(StreamStateHandling::parseDate)
.peek(v->{if(!v.isPresent())addResult(Status.ERROR);})
.filter(可选::isPresent)
.map(可选::get)
.map(DayOfWeek::from)
.peek(v->addResult(Status.SUCCESS))
.forEach(System.out::println);
系统输出打印项次(结果);
}
公共静态void main(字符串参数[]){
新StreamStateHandling().doWork();
}
私有void addResult(状态){
int current=results.getOrDefault(状态为0);
结果。put(状态,当前+1);
}
}
基本上,我们是在地图中跟踪状态计数。这在单线程处理中工作良好,但在并行流中产生不确定性输出

在现实世界中,我们有几种状态和操作链。一般来说,什么是最好的工具流和跟踪进度的方法?我更喜欢香草Java8实现,但如果使用开源库更容易实现的话可以


非常感谢您的帮助。

EnumMap
不是线程安全的,而且
addResult()
中的读-修改-写逻辑也不是线程安全的。尝试使用原子计数器增加计数:

private Map<Status, Integer> results = new ConcurrentHashMap<>();

private void addResult(Status status) {
    results.merge(status, 1, Integer::sum);
}
private Map results=new ConcurrentHashMap();
私有void addResult(状态){
结果.合并(状态,1,整数::和);
}

Nice!。我不知道
merge()
函数。在实际实现中,我必须按两个维度跟踪计数,我使用的是google guava表,它还不支持同步实现。总的来说,这是一个好方法吗?我们正试图通过使用并发处理来加快速度,但同步到跟踪状态可能会使速度变慢。@Raja我可以想出一些选择。a) 使用带有复合键的
ConcurrentHashMap
,而不是
。b) 使用
AtomicInteger
s预填充表,可以在不锁定的情况下安全地递增。c) 围绕
addResult()
同步。正如您所提到的,这可能是一个严重的并行化瓶颈,具体取决于流的其余部分正在进行多少处理。更一般地说,我认为您的场景是否是流的一个良好用例是值得怀疑的。流通常应具有有限的副作用,并产生单一的聚合结果。您试图从一个流中生成多个结果值。
.peek.foreach
似乎是多余的。您可以将forEach转换为一个同时满足这两个角色的函数。