netty的几个重要特性
1.一个EventLoopGroup当中包含一个或多个EventLoop
2.一个EventLoop在其生命周期内只和唯一的一个Thread线程绑定(即一个io线程)
3.所有由EventLoop处理的各种io事件都将在其所关联的io线程上执行,因为是单线程保证了线程安全
4.一个Channel在其生命周期内只会注册在一个EventLoop(selector)上
5.运行期间,一个EventLoop会被分配给一个或多个channel
重点来看第三点netty是如何实现的呢?
其中eventLoop.inEventLoop()方法的逻辑是:
判断当前线程是否是EventLoop中所绑定的那个唯一的io线程
如果是,则直接执行相应的channelHandler,处理该io事件
若不是,则将需要执行的channelHandler封装成一个任务交给EventLoop中io线程去执行,EventLoop中具体保存任务的是一个FIFO队列,而且又是单线程执行,所以在保证线程安全的同时也保证了任务的有序性。
(这里同时要注意的是,在channelHandler中要避免执行耗时或阻塞的处理逻辑,这样会导致后续channelHandler或其他绑定在该EventLoop上的channel的事件响应阻塞,从而影响性能。解决方式:耗时任务或阻塞的任务在自定义的channelHandler中可以交给业务线程池去处理,从而避免阻塞)
重要结论:
netty中,channel的实现一定是线程安全的,基于此,我们可以存储一个channel的引用,并且在需要向远端发送数据时,通过这个引用来写数据,即便当时有很多线程在使用它也不会出现线程安全的问题,而且消息一定是按照顺序发送的