Split Array into Multiple Threads

0

I need to make a Query in my Database, which will return each of the Lines. However, for each of them, during the Retorno, I have to wait about 5 seconds, because it is the time that I have to wait for Ping to complete and return to me if the Host is standing or not.

@GetMapping
public Iterable<MonitoriaEntidade> resposta() throws UnknownHostException, IOException{

    Iterable<MonitoriaEntidade> findAll = monitoriaRepositorio.findAll();

    for (MonitoriaEntidade monitoriaEntidade : findAll) {
        if (InetAddress.getByName(monitoriaEntidade.getIp()).isReachable(5000)) monitoriaEntidade.setStatus(true);
    }

    return findAll;
}

My question is: How do I separate this Query into several different Threads, so that I do not do just one at a time, but preferably how much the Server can do.

    
asked by anonymous 23.11.2018 / 01:28

1 answer

3

You can do this through stream in parallel. But for this, it is first necessary to "hide" the exception for a RuntimeException ( read more ).

Let's go through a RTE that loads UnknownHostException or IOException , to use it within the lambda expression:

class WrapperException extends RuntimeException {
    final UnknownHostException uhe;
    final IOException ioe;

    WrapperException(UnknownHostException uhe) {
      super(uhe);
      this.uhe = uhe;
      this.ioe = null;
    }

    WrapperException(IOException ioe) {
      super(ioe);
      this.uhe = null;
      this.ioe = ioe;
    }

    void throwWrappedException() throws UnknownHostException, IOException {
      if (this.uhe != null) throw uhe;
      if (this.ioe != null) throw ioe;
    }
}

Now, let's turn the inside of your loop into a method that does not throw an exception checked, transforming it into WrapperException :

void setStatusMonitoriaEntidade(MonitoriaEntidade monitoriaEntidade) {
  try {
    if (InetAddress.getByName(monitoriaEntidade.getIp()).isReachable(5000)) {
      monitoriaEntidade.setStatus(true);
    }
  } catch (IOException e) {
    throw new WrapperException(e);
  } catch (UnknownHostException e) {
    throw new WrapperException(e);
  }
}
So if hypothetically the findAll method returns a Collection (as a List ), we can turn that loop for into a parallelStream :

@GetMapping
public List<MonitoriaEntidade> resposta() throws UnknownHostException, IOException {
    List<MonitoriaEntidade> findAll = monitoriaRepositorio.findAll();

    try {
      findAll.parallelStream().forEach(this::setStatusMonitoriaEntidade);
    } catch (WrapperException e) {
      // se um dos processamentos der ruim, lança a exceção; mesmo comportamento anterior
      e.throwWrappedException();
    }

    return findAll;
}

In my experiments (I did not find the official documentation on the subject), making these calls through parallelStream uses the maximum number of cores available for processing, but does not create threads beyond what can actually be consumed. / p>

On the other hand, this is not the case, as you reminded me. However, almost nothing is lost. You have a great Baeldung article on the subject. It fixes this using StreamSupport :

@GetMapping
public Iterable<MonitoriaEntidade> resposta() throws UnknownHostException, IOException {
    Iterable<MonitoriaEntidade> findAll = monitoriaRepositorio.findAll();

    try {
      StreamSupport.stream(findAll.spliterator(), true).forEach(this::setStatusMonitoriaEntidade);
    } catch (WrapperException e) {
      // se um dos processamentos der ruim, lança a exceção; mesmo comportamento anterior
      e.throwWrappedException();
    }

    return findAll;
}
    
23.11.2018 / 13:55