Summarization of several methods of asynchronous non blocking programming in Java

  • 2021-10-13 07:47:56
  • OfStack

1 server-side execution, the simplest synchronous call method:

Defects: Before the server responds, IO will block in: On the native method of java. net. SocketInputStream # socketRead0:

2 JDK NIO & After Future java 1.5

Advantages: The main thread can do something else without waiting for IO response, for example, send another IO request and wait until one returns; Disadvantages: The main thread still needs to wait in the process of waiting for the result to return, which does not fundamentally solve this problem;

3 Use Callback callback mode

Advantages: After the main thread completes sending the request, it no longer needs to care about this logic and execute other logic; There is no thread blocking in the whole process; For example, the thread in EventLoopGroup using nio executes all logic; Disadvantages: callback to hell; Callback hell; The code is low readability, difficult to write and error-prone

4 JDK 1.8 CompletableFuture

Advantages: Solve the problem of Callback Hell, and CompletableFuture is provided in JDK 1.8; Every IO operation can be encapsulated as a separate CompletableFuture, thus avoiding callback hell. Implementation: Encapsulate the inverse Callback logic into an independent CompletableFuture, when the asynchronous thread calls back, call future. complete (T), and encapsulate the result; thenCompose connection, whenComplete output; Summary: In this way, the callback hell problem is perfectly solved. In the main logic, it seems to be coding synchronously.

5 source code example test + result


 
import java.util.concurrent.CompletableFuture; 
public class CompletableFutureTest { 
    private static CompletableFuture<String> invokeAFuture(String rawASource){
        CompletableFuture<String> future = new CompletableFuture<>();
        System.out.println("pre-do-invokeA");
        try {
            Thread.sleep(1000);
            future.complete("invokeA "+rawASource+" result = skip");
        }catch (Exception e){
 
        }
        return future;
    }
 
    private static CompletableFuture<String> invokeBFuture(String rawAResult){
        CompletableFuture<String> future = new CompletableFuture<>();
        System.out.println("pre-do-invokeB");
        try {
            Thread.sleep(1000);
            future.complete("after A done result = "+rawAResult+", then invokeB result = success");
        }catch (Exception e){
 
        }
        return future;
    }
 
    public static void main(String[] args) {
        invokeAFuture(" Refueling ").thenCompose(aResult-> invokeBFuture(aResult)).whenComplete((resultB, throwable) ->{
            if(throwable != null){
                throwable.printStackTrace();
                return;
            }
            System.out.println(resultB);
        });
    }
    
     public static void main(String[] args) {
        invokeAFuture(" Refueling ").thenCompose(CompletableFutureTest::invokeBFuture).whenComplete((resultB, throwable) ->{
            if(throwable != null){
                throwable.printStackTrace();
                return;
            }
            System.out.println(resultB);
        });
    }
} 
pre-do-invokeA
pre-do-invokeB
after A done result = invokeA  Refueling  result = skip, then invokeB result = success

6 Summary:

1 Try to use asynchronous programming; 2. Analyze the internal realization principle; 3 java9 juc packet has a more abstract flow processing mode;

Java asynchronous programming best practices

What is asynchronous? Why use it?

Asynchronous programming provides a non-blocking, event-driven programming model. This programming model provides parallelism by utilizing multi-core execution tasks in the system, thus providing application throughput. Throughput rate here refers to the number of tasks done per unit time. In this way, a unit of work executes independently of the main application thread and notifies the calling thread of its status: successful, in process, or failed.

We need asynchronous to eliminate the blocking model. In fact, the asynchronous programming model can use the same thread to process multiple requests without blocking the thread. Imagine a thread being used by an application executing a task, and then waiting for the task to complete before proceeding to the next step. The log framework is a good example: Typically you want to log exceptions and errors to a target, such as a file, database, or something like that. You won't let your program wait for the log to be written before executing, otherwise the response of the program will be affected. Conversely, if calls to the log framework are asynchronous, applications can perform other tasks concurrently without waiting. This is an example of non-blocking execution.

To implement asynchronism in Java, you need to use Future and FutureTask, which are under java. util. concurrent packages. Future is an interface and FutureTask is an implementation class. In fact, if you use Future in your code, your asynchronous task executes immediately, and the calling thread gets the result promise.

What to do and what not to do

To facilitate testing, you should isolate functions from multithreading in your code. When writing asynchronous code in Java, you should follow the asynchronous model so that the calling thread is not blocked.

Note that constructors cannot be asynchronous, and you should not call asynchronous methods in constructors. The asynchronous approach is especially useful when tasks are independent of each other. Asynchrony should not be used when the calling task depends on the called task.

You should handle exceptions in asynchronous methods. You should not implement exceptions for long-running task. A long-running task, If executed asynchronously, it may take longer than synchronous execution, because the runtime performs thread context switching, thread state storage, etc. for asynchronous execution methods. You should also note that synchronous exceptions are different from asynchronous exceptions.

Synchronization exception implies that an exception will be thrown every time a program executes to a special state of that program; Tracing asynchronous exceptions is much more difficult.

So synchronous and asynchronous exceptions imply that synchronous or asynchronous code may throw exceptions

synchronous and asynchronous exceptions imply synchronous or asynchronous code in your program that might raise exceptions.


Related articles: