preface

I don’t want to write fancy words, just say the problem and how to deal with it.

There are two interfaces A and B, A is to obtain A certain range of user name list, interface B is based on the name of the user to find the user’s hobbies, so to display the data in the ListView interface A +B interface, how elegant write?

I’m going to call interface A first, and then loop through interface B, right? , the request callback of interface B is associated with the specified name, and then the adapter is set up.

Different people have different ways of writing it, so LET’s go straight to what I think is more elegant.

import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionService
import java.util.concurrent.ExecutorCompletionService
import java.util.concurrent.ExecutorService
import java.util.function.Supplier
import java.util.stream.Collector
import java.util.stream.Collectors
import java.util.stream.Stream

fun syncPost(name: String): String {
    return "The hobbyThe ${(0.10.).random()}"
}

var map = mutableMapOf<String, String>()
fun getHobby(name: String, map: MutableMap<String, String>): CompletableFuture<Unit> {
    return CompletableFuture.supplyAsync {
        Thread.sleep((0.1000.).random().toLong())
        map[name] = syncPost(name)
    }
}

fun main(a) {
    var listName = Stream.generate { "LiThe ${(0.10.).random()}" }.limit(10).collect(Collectors.toSet())
    var exec = mutableListOf<CompletableFuture<Unit>>()
    println(map)
    listName.forEach {
        exec.add(getHobby(it, map))
    }
    var allOf = CompletableFuture.allOf(*exec.toTypedArray()).thenAccept {
        println("Execution completed")
        println(map)
    }
    allOf.get()}Copy the code

Again, the principle is CompletableFuture. First, CompletableFuture is an extension of The Future, meaning it’s stronger, and it solves something that the Future can’t do. In this case, it does something that the Future can’t do, which is execute multiple asynchronous tasks together.

A more convenient method, CompletableFuture, provides a callback that is called after all the tasks have been completed, the thenAccept method. If you loop through the request, how do you know that all the requests have been completed? Do you need a variable summation or some other method, but feel there is no thenAccept convenient.

We can also specify a time out and throw a TimeoutException if the time is not complete.

try {
    allOf.get(500, TimeUnit.MILLISECONDS)
} catch (ep: TimeoutException) {
    ep.printStackTrace()
}
Copy the code

In addition, if the exception is not caught in the task, it will not affect other tasks, but it will not execute thenAccept. Note that if an exception is thrown in the task, it will not be output immediately, but will be actually thrown after the entire task has finished.

fun getHobby(name: String, map: MutableMap<String, String>): CompletableFuture<Unit> {
    return CompletableFuture.supplyAsync {
        Thread.sleep((0.1000.).random().toLong())
        map[name] = syncPost(name)
        if (name == "Lee 2")
            throw  NullPointerException("null")
        println(${thread.currentThread ().name})}}Copy the code

If a task fails, it needs to be added to a retry queue.