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 name | JdkFuture | NettyFuture | Promise |
---|---|---|---|
cancel | Cancel task | ||
isCanceled | Cancel task | ||
isDone | Whether the task is completed or not cannot distinguish success from failure | ||
get | Get task results, block and wait | ||
getNow | Get the task result, non blocking, and return Null if the result has not been generated | ||
await | Wait for the task to end. If the task fails, no exception will be thrown, but it needs to be judged by isSuccess | ||
sync | Wait for the task to end. If the task fails, throw an exception | ||
isSuccess | Judge whether the task is successful | ||
cause | Get the failure information, non blocking. If there is no failure, null is returned | ||
addLinstener | Add callback to receive results asynchronously | ||
setSuccess | Setting result succeeded | ||
setFailure | Failed 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.