EventLoop介绍
在Netty中使用EventLoop接口代表事件循环,EventLoop是从EventExecutor和ScheduledExecutorService扩展而来,所以可以讲任务直接交给EventLoop执行
可以进行各种骚操作
每个通道需要注册到一个EventLoop来处理IO或事件,这是在引导过程中自动完成
//nio java.nio.channels.SocketChannel mySocket = java.nio.channels.SocketChannel.open(); //netty SocketChannel ch = new NioSocketChannel(mySocket); EventLoopGroup group = new NioEventLoopGroup(); //register channel ChannelFuture registerFuture = group.register(ch); //de-register channel ChannelFuture deregisterFuture = ch.deregister();
EventLoop.register(...)和Channel.deregister(...)都是非阻塞异步的,也就是说它们可能不会理解执行完成,可能稍后完成。它们返回ChannelFuture,我们在需要进一步操作或确认完成操作时可以添加一个ChannelFutureLister或在ChannelFuture上同步等待至完成;选择哪一种方式看实际需求,一般建议使用ChannelFutureLister,应避免阻塞。
挂起IO处理
EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioSocketChannel.class) .handler(new SimpleChannelInboundHandler<ByteBuf>() { @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { //remove this ChannelHandler and de-register ctx.pipeline().remove(this); ctx.deregister(); } }); ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.baidu.com", 80)).sync(); //.... Channel channel = future.channel(); //re-register channel and add ChannelFutureLister group.register(channel).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if(future.isSuccess()){ System.out.println("Channel registered"); }else{ System.out.println("register channel on EventLoop fail"); future.cause().printStackTrace(); } } });
迁移通道到另一个事件循环
另一个取消注册和注册一个Channel的用例是将一个活跃的Channel移到另一个EventLoop,有下面一些原因可能导致需要这么做:
- 当前EventLoop太忙碌,需要将Channel移到一个不是很忙碌的EventLoop;
- 终止EventLoop释放资源同时保持活跃Channel可以继续使用;
- 迁移Channel到一个执行级别较低的非关键业务的EventLoop中。
EventLoopGroup group = new NioEventLoopGroup(); final EventLoopGroup group2 = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class) .handler(new SimpleChannelInboundHandler<ByteBuf>() { @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { // remove this channel handler and de-register ctx.pipeline().remove(this); ChannelFuture f = ctx.deregister(); // add ChannelFutureListener f.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { // migrate this handler register to group2 group2.register(future.channel()); } }); } }); ChannelFuture future = b.connect("www.baidu.com", 80); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { System.out.println("connection established"); } else { System.out.println("connection attempt failed"); future.cause().printStackTrace(); } } });