理解异步
用实际场景来理解异步。
场景一: 餐厅就餐(人物:小张和服务员)
同步:小张点完餐后把单子交给服务员,之后就不停询问服务员饭菜是否已被准备好。如果准备好了,就自己去端饭菜;如果没准备好,就过一会再询问。
异步:小张点完餐后把单子交给服务员,后续就坐等服务员把饭菜主动端到餐桌上。中途可以看看手机打发时间。
对比同步或异步,异步明显给小张的用户体验更好。
场景二:Netty ChannelFuture
以服务端启动来说,启动过程中主线程会生成一个RegisterChannelFuture,主线程第一次提交任务(任务会引用RegisterChannelFuture)到NioEventLoop时会启动NioEventLoop线程并返回。主线程然后再往RegisterChannelFuture注册listener回掉函数。当任务在NioEventLoop线程中执行完后,会主动调用RegisterChannelFuture中的listener回掉函数。
对于此场景,当主线程注册完listener回掉函数后,就可以继续做其他事情。
异步实例
import java.util.ArrayList;
public class Main {
public static void main(String[] args){
final Future future = new Future();
Thread thread = new Thread(()->{
try{
Thread.sleep(10000);
} catch (Exception e){
}
future.setSuccess();
});
thread.start();
future.addListener(()->{
System.out.println("async call successfully.");
});
}
private static class Future {
private volatile int status;
private ArrayList<Listener> listeners;
public Future() {
status = 0;
listeners = new ArrayList<>();
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public void setSuccess() {
setStatus(1);
// notify listeners.
for(Listener listener : listeners) {
listener.onCompleted();
}
}
public void addListener(Listener listener){
listeners.add(listener);
}
}
interface Listener{
void onCompleted();
}
}
说明:
主线程中创建了一个Future实例并创建和启动了一个新线程(新线程可以调用future实例),之后主线程引用了注册了一个listener回掉函数。这里例子能实现异步的一个关键点在于有一个future共享变量,在JVM创建thread对象后,此变量作为thread.run方法的形参传入,所以新线程能访问future变量(如下图标红字节码部分)。
网友评论