Netty component Future&Promise

Posted by Hepp on Sat, 01 Jan 2022 02:09:03 +0100

Future&Promise

  • Future in Netty has the same name as future in JDK, but these are two interfaces. Future in Netty inherits from the future interface in JDK, and Promise inherits from the future interface in Netty.
  • The Future function of JDK is weak. You can only get results after * * synchronization and waiting * * task ends (or succeeds or fails)
  • netty Future can wait for the task to end synchronously or get the result asynchronously, but it still needs to wait for the task to end
  • Netty promise not only has the function of nettyFuture, but also exists independently of tasks. It is not passive and can only wait for results. It can be used as a container for transmitting results between two threads
Function nameJdkFutureNettyFuturePromise
cancelCancel task
isCanceledCancel task
isDoneWhether the task is completed or not cannot distinguish success from failure
getGet task results, block and wait
getNowGet the task result, non blocking, and return Null if the result has not been generated
awaitWait for the task to end. If the task fails, no exception will be thrown, but it needs to be judged by isSuccess
syncWait for the task to end. If the task fails, throw an exception
isSuccessJudge whether the task is successful
causeGet the failure information, non blocking. If there is no failure, null is returned
addLinstenerAdd callback to receive results asynchronously
setSuccessSetting result succeeded
setFailureFailed to set result

JdkFuture

Future is a container for transferring results or data between processes. Here, the future of jdk is passive and must be filled into future by the thread executing the task, not actively

package d2;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.concurrent.*;

/**
 * @BelongsProject: netty_learn
 * @BelongsPackage: d2
 * @Author: Wang Haipeng
 * @CreateTime: 2021-12-28 14:30
 * @Description: jdkfuture test
 */
@Slf4j
public class TestJdkFuture {

    @Test
    public void test1() throws ExecutionException, InterruptedException {
        /*1,Thread pool
        JDKFuture It is often used by the associated thread pool*/
        ExecutorService service = Executors.newFixedThreadPool(2);
        /*2,Submit task
        The two parameters, Callable and Runnable, are both tasks, but Callable has a return value
        The detailed logic and calculation are the threads in the thread pool, but the main thread needs to get the result
        Use future to let the main thread communicate with the threads in the thread pool, and obtain the results after the execution of the child thread through future
        */
        Future<Integer> future = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.debug("perform calculation");
                Thread.sleep(1000);
                return 50;
            }
        });
        /**
         * 2,The main thread obtains the results through future
         * Here, the main thread will block and wait for the calculation of the child thread synchronously, and the task result will be obtained through get
         * When the thread computer in the thread pool ends, wake up the main thread and print out
         */
        log.debug("Waiting for results");
        Integer integer = future.get();
        log.debug("The calculation result of the child thread is:{}",integer);
    }
}

NettyFuture

@Slf4j
public class TestNettyFuture {

    @Test
    public void test(){

        /*1,EventLoop
        It also needs to be based on thread pool, but the thread pool in Netty is called EventLoop, but there is only one thread in this thread pool
        NioEventLoopGroup There are multiple eventloops in, but each EventLoop has only one thread
        */
        NioEventLoopGroup eventLoopGroup =new NioEventLoopGroup();
        EventLoop eventLoop = eventLoopGroup.next();

        /*2,Submit task*/
        Future<Integer> future = eventLoop.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.debug("perform calculation");
                return 50;
            }
        });

        future.addListener(new GenericFutureListener<Future<? super Integer>>() {
            @Override
            public void operationComplete(Future<? super Integer> future) throws Exception {
                /*The premise of calling the callback method is that the task has been executed, so there is no need to block. This is also the relationship between the callback method and asynchrony
                * So there is no difference between get() and getNow()
                * 
                * TODO:Why is it OK to execute here but do not print the log?
                * */
                log.debug("{}",future.getNow());
            }
        });
    }
}

Execute future. By addListener Getnow () is performed by the executing thread, not the main thread

NettyPromis

The future objects in JdkFuture and NettyFuture are not created actively, but the results returned when the thread executes

Child thread load result:

promise is created actively, which is essentially different from the passively created future itself

package d2;

import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.ExecutionException;

/**
 * @BelongsProject: netty_learn
 * @BelongsPackage: d2
 * @Author: Wang Haipeng
 * @CreateTime: 2021-12-28 15:48
 * @Description: promise Test class
 */
@Slf4j
public class TestNettyPromise {

    @Test
    public void test() throws ExecutionException, InterruptedException {

        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        EventLoop eventLoop = eventLoopGroup.next();
        /*1,Promise can be actively created as a container for results, not necessarily*/
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);

        new Thread(()->{
            log.debug("Start calculation");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /*2,Any thread executes the task and loads the calculation results after calculation*/
            promise.setSuccess(50);
        },"Computing thread").start();

        /*3,Receive results*/
        log.debug("Waiting for results");
        System.out.println(promise.get());
    }
}

You can not only fill in the calculation results, but also fill in exceptions

Sub thread loading exception:

package d2;

import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.ExecutionException;

/**
 * @BelongsProject: netty_learn
 * @BelongsPackage: d2
 * @Author: Wang Haipeng
 * @CreateTime: 2021-12-28 15:48
 * @Description: promise Test class
 */
@Slf4j
public class TestNettyPromise {

    @Test
    public void test() throws ExecutionException, InterruptedException {

        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        EventLoop eventLoop = eventLoopGroup.next();
        /*1,Promise can be actively created as a container for results*/
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);

        new Thread(()->{
            log.debug("Start calculation");
            try {
                Thread.sleep(1000);
                throw new RuntimeException("Calculation error!");
            } catch (RuntimeException e) {
                /*Delivery exception*/
                promise.setFailure(e);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"Computing thread").start();

        /*3,Receive results*/
        log.debug("Waiting for results");
        try {
            log.debug(String.valueOf(promise.get()));
        } catch (Exception e){
            log.error(e.getMessage());
        }
    }
}

todo: still don't feel the greater difference between promise and future? For example, whether promise can be passed from the main thread to the child thread value is found after testing here

promise.setSuccess wants promise to be equal to null, that is, it will not be assigned. We do not intend to study it in depth here. We will study it when we study the source code as a whole. Only records are made here.

Topics: Java Netty