1 EventLoop
EventLoop 本质是一个单线程执行器(同时维护了一个 Selector),里面有 run 方法处理 Channel 上源源不断的 io 事件(事件循环对象)。
2 EventLoopGroup
2.1 Channel绑定EventLoop
EventLoopGroup 是一组 EventLoop,Channel 一般会调用 EventLoopGroup 的 register 方法来绑定其中一个 EventLoop,后续这个 Channel 上的 io 事件都由此 EventLoop 来处理(保证了 io 事件处理时的线程安全)。
EventLoopGroupServer:
@Slf4j
public class EventLoopGroupServer {
public static void main(String[] args) {
new ServerBootstrap().group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info((String) msg);
}
});
}
}).bind(8888);
}
}
EventLoopGroupClient:
public class EventLoopGroupClient {
public static void main(String[] args) {
new Thread(() -> {
try {
sendMsg("Hi 张三");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
sendMsg("Hi 李四");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
sendMsg("Hi 王五");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
private static void sendMsg(String msg) throws InterruptedException {
Channel channel = new Bootstrap().group(new NioEventLoopGroup()).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
}
}).connect(new InetSocketAddress("localhost", 8888))
.sync().channel();
channel.writeAndFlush(msg);
Thread.sleep(3000);
channel.writeAndFlush(msg);
}
}
结果:
2.2 细分EventLoopGroup职责
细分NioEventLoopGroup为boss、worker,boss只负责NioServerSocketChannel上accept事件、worker只负责socketChannel上读写。
new ServerBootstrap()
//细分NioEventLoopGroup为boss、worker
//boss只负责NioServerSocketChannel上accept事件、worker只负责socketChannel上读写
.group(new NioEventLoopGroup(), new NioEventLoopGroup(2))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info((String) msg);
}
});
}
}).bind(8888);
创建一个DefaultEventLoop来处理比较耗时的handler。防止某一个比较耗时的handler影响其他客户端的读写操作(一个EventLoop 管理很多channel )。
EventLoopGroupServer:
@Slf4j
public class EventLoopGroupServer {
public static void main(String[] args) {
EventLoopGroup group = new NioEventLoopGroup(2);
new ServerBootstrap()
//细分NioEventLoopGroup为boss、worker
//boss只负责NioServerSocketChannel上accept事件、worker只负责socketChannel上读写
.group(new NioEventLoopGroup(), new NioEventLoopGroup(2))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder());
//handler1 处理完消息将消息传递给下一个handler
ch.pipeline().addLast("handler1", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info("handler1 read msg:{}", msg);
ctx.fireChannelRead(msg);
}
});
//
ch.pipeline().addLast(group, "handler2", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info("handler2 read msg:{}", msg);
}
});
}
}).bind(8888);
}
}
EventLoopGroupClient:
public class EventLoopGroupClient {
public static void main(String[] args) throws InterruptedException {
Channel channel = new Bootstrap().group(new NioEventLoopGroup()).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
}
}).connect(new InetSocketAddress("localhost", 8888))
.sync().channel();
channel.writeAndFlush("Hello Netty");
}
}
group 线程和worker 线程不一样