在这里我们以服务端启动为例,此篇文章适合对Netty有一定基础的读者.
在服务端开发中,启动服务端的部分代码如下
NioEventLoopGroup boss = new NioEventLoopGroup(1); NioEventLoopGroup worker = new NioEventLoopGroup(); ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(boss, worker).channel(NioServerSocketChannel.class) .handler(new ChannelInitializer<ServerSocketChannel>() { @Override protected void initChannel(ServerSocketChannel ch) throws Exception { ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new StringEncoder()); ch.pipeline().addLast(new BusinessInHandler()); } }) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { // ... } }); serverBootstrap.bind("127.0.0.1", 8080).sync();
最后一行代码
serverBootstrap.bind("127.0.0.1", 8080).sync();
会以同步的方式,阻塞的等待端口绑定成功.
我们换种方式写这行代码,分开书写
ChannelFuture bindFuture = serverBootstrap.bind("127.0.0.1", 8080); System.out.println("mark1= " + bindFuture); ChannelFuture syncFuture = bindFuture.sync(); System.out.println("mark2= " + syncFuture);
执行并打印
我们发现,这两个Future是同一个对象.
是的,它们的确是同一个对象
但是,细心的你会发现
同一个对象,但是它们的状态在不同的时刻是不同的.
看过我之前写的Netty文章,或者读者已经有了Netty基础,那么应该会理解.
主线程main在执行的过程中,会负责启动一个IO线程,这个IO线程才会负责真正的端口绑定任务. 在我们第一次拿到的bindFuture时,IO线程还没有完成端口绑定,因此我们看到的值就是图上的incomplete. 之后main线程调用sync同步阻塞等待绑定任务完成,
当IO线程完成绑定任务,唤醒main线程,这个时候main线程拿到的syncFuture值就是success.
假设main线程执行的比较慢,而IO线程绑定端口执行的非常快,那么我们就会看到两个success.
我们也可以模拟测试验证一下
这里我们通过debug方式,故意让main线程阻塞住,目的就是让IO线程先执行完绑定端口任务.
【注意】
打完debug之后,右击断点,选择Thread方式.
我们再次执行,断点停留稍等一小会再放开.
我们就会看到相同的状态了,这个状态就表示端口绑定完成.