Split Array into Multiple Threads

Asked

Viewed 241 times

0

I need to do a Query in my Database, which will return each of the Lines. However, for each of them, during the Return, I need to wait about 5 seconds, because it is the time I need to wait for Ping to complete and return 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 only one at a time, but preferably how much the Server can.

  • You have to have a pool of connections with the bank, ie each thread will have to separately make your call to the bank and do the search, since each connection supports only one object (the call). As for the threads, search for ExecutorService, which is an API core Java to handle a pool of threads asynchronously. Take a look at CompletableFuture also, which is for the asynchronous return of your method (your search) to be stored and manipulated.

  • 1

    @Statelessdev, for the threaded part, I think it’s best to use parallelStream. This avoids you, as a programmer, having to deal explicitly with parallelism, when this particular parallelism has every way of being totally non-compete. Seems like a typical scenario I just have to wait for joins threads

1 answer

3


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

Let’s put a TEN 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 inner part of your loop into a method that doesn’t throw exception checked, that turns them 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 method findAll return a Collection (as a List), we can transform that bond for in 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), make these calls through parallelStream uses as many cores as possible for processing, but does not create threads beyond what can actually be consumed.

On the other hand, this is not the case, as you reminded me. However, almost nothing is lost. It has a great article by Baeldung on the subject. He resolves it 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;
}
  • 1

    Excellent, Jefferson. Just a silly detail you surely know: you can use the logical operator | in the catch, taking the two exceptions and saving a catch and a throw thereby.

  • 1

    @Statelessdev I just wanted to ensure the correct call from the builder. As I wrote this without being on a computer, I was left with doubts whether the javac could correctly solve which of the builders to call, so I preferred to be explicit. I don’t know what kind of e using the multi-catch when deciding which constructor to call...

  • The problem I’m having is that the parallelStream() method is not available in Iterable, which I need to do in order to use it?

  • 1

    @Fernandocampanate forgive my carelessness, I swear I had seen Collection or List. You need to turn into a Stream and parallelize. I’ll edit the answer

  • @Fernandocampanate as you have again marked my answer as accepted, I am judging that your tests have worked. Check? If there is any doubt about things left in this reply, or if you have something in your doubt not yet contemplated, you can go here and I will try to supplement the answer

  • I was able to implement what you said, but I’m still trying to make it work. 'Cause before I was using the Lambda, as soon as I have a conclusion, I’ll answer you here.

  • IT WORKED!!! And extremely fast!

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.