因为前段时间的项目需要写一些高性能服务器,结果写出来的结果是五花八门,我们要求使用NIO编写异步服务器,但是竟然有人把NIO硬生生地写成同步的,还写成了一个单道批处理,线程调度、通信、同步操作,尤如天马行空,看不出一点架构,典型的面条代码,极度晕倒,不得不下定决心,将IO部分与线程调度部分隔离出来。
为此,狠下心来,仔细研究了一下nio机制和dl的util.concurrent包。
一、NIO的出现
NIO是JDK1.4里面才出现的东东,他给大家带来的最大好处是异步socket。其它file,pipe暂时就不多谈了。
在JDK1.4出现之前,如果你需要编写一个Java服务器,为了实现异步操作,你必须为每个连接请求生成一个Java线程,当连接请求很多时,线程的调度,上下文切换,所付出的代价是非常昂贵,而且由于Java是跨平台的,各个平台对线程的支持并不相同,性能也不相同,因此传统的Java服务器编程架构是低效的且代价贵,dl大侠写了个util.concurrent包后,总算是减轻了线程调度给java程序员带来的痛苦,但是相比之与C、C++写出来的服务器,java服务器在性能要求很高的情况下,基本上没有什么竞争力,甚至是入围的权利的都没有。
二、异步socket的实现
NIO出现后,好像让java的程序员有了杨眉吐气的机会,怎么个吐气法,当时大家是个什么感受,俺是不知道,因为当时俺不搞java,对java的认识有限。
NIO是一个基于事件的IO架构,最基本的思想就是:有事件我通知你,你再去做你的事情,没事件时你大可以节约大把时间去做其它任何事情。而且NIO的主线程only one,不像传统的模型,需要N个线程去,也减轻了JVM的工作量,使得JVM处理任务时显得更加高效。
刚开始接触NIO时,被N层的Channel架构、网上铺天盖地的好评给镇住了,想想也应当是个很成熟的产品了,网上资料这么多,抄一抄Jetty、Tomcat以及其它一些牛B的源代码,基本上就能搞定了,此时没有想到大家受同步的影响这么深,也没有想到连最基本的异步概念都没有搞清楚就去写代码,搞出一堆的问题来(这是后话,后面再说)。
现在研究了NIO以后,发现NIO实际上在Java中做的工作是很简单,就是将事件进行收集和分发,我们结合一个经典的调用例子来说明这个问题,我就不从NIO的基本使用说起了,大家可以查其它的资料,网上一大把。
当Channel注册至Selector以后,我们的最经典的调用方法,是这样子的。
1while(somecondition)
2{
3intn=selector.select(TIMEOUT);
4if(n==0)continue;
5for(Iteratoriter=selector.selectedKeys().iterator();iter.hasNext();)
6{
7if(key.isAcceptable())
8doAcceptable(key);
9if(key.isConnectable())
10doConnectable(key);
11if(key.isValid()&&key.isReadable())
12doReadable(key);
13if(key.isValid()&&key.isWritable())
14doWritable(key);
15iter.remove();
16}
17}
这只是个小例子啊,什么异常我就懒得抓了。
nio中取得事件通知,就是在selector的select事件中完成的,在selector事件时有一个线程,这个线程具体的处理简单点说就是:向操作系统询问,selector中注册的Channel&&SelectionKey的偶对各种事件是否有发生,如果有则添加到selector的selectedKeys属性Set中去,并返回本次有多少个感兴趣的事情发生。程序员发现这个值>0,表示有事件发生,马上迭代selectedKeys中的SelectionKey,根据Key中的表示的事件,来做相应的处理。
实际上,这段说明表明了异步socket的核心,即异步socket不过是将多个socket的调度(或者还有他们的线程调度)全部交给操作系统自己去完成,异步的核心Selector,不过是将这些调度收集、分发而已。因为操作系统的socket、线程调度再咋D也比你JVM中要强,效率也高。
而且就算jvm做的和操作系统一样好,性能一样高(当然这是不现实的),使用异步socket你至少也节约了一半的系统消耗,想想假定操作系统本身也是使用线程来维护N个socket连接,在传统的java编程中,你还必须为这些socket还多起一个java线程,那至少是2N个线程,现在只需要N+1。在高并发的情况下,你自己去想吧。
懂了这个道理,异步socket也就好写了,也不会搞得思路混乱了。
三、 异步Socket中应当注意的事情
3.1 读
异步socket最基本的理念就是事件通知,前面也说了,有事件通知你了,你才该做你应当做的事情。在异步socket中当注册了一个OP_READ事件后,你就等着Selector通知你吧,如果没有通知你,你在家睡大觉都行。
在这里,我们有人出现的错误就是受同步的影响,自己去主动读,而且还搞出了多线程,如果仔细考虑一下,就不会出现这个问题了。同步socket中,调用read方法读取IO中的数据时,通常情况下如果没有数据read方法会阻塞,且是同步的,所以当多个线程同时访问时,read方法是线程安全的。
而在异步下就不同,异步是不会阻塞的,有什么就返回什么,你主动去读,只要有数据,你就可以拿走,在多线程的情况下,也许你是想让第一个线程读取,but此时来数据时正好是线程2读到了,那线程2就高高兴兴的拿去,而线程1还在苦苦等待,这样导致数据混乱不说,如果后面再也不来数据了,线程1就是死循环啦。
2. 写
在异步socket中,写是唯一一个主动点的操作,但是也不能直接去写Channel,而是应当先把自身注册为OP_WRITABLE,这时Selector就会发现你的存在,并把给发一个write事件,你这时后就可以写了,不过这时候有个小小的技巧,就是你执行写操作之前,请取消掉你的写注册,否则你的cpu肯定是100%。
3. 等待
在传统的服务器编程中,由于对于每个请求都是产生的一个线程,因此你在你每个请求线程中wait也好,sleep也好,不会影响别人。但是异步不同,他的主线程只有一个,基本上每个处理都是线性的,也就是说处理完第一个,然后才能处理第二个,因此nio是一个极好的处理短连接的架构。
我们现在出现的问题是,有人受同步的影响,没有搞清异步是如何处理,竟然在方法处理中用上sleep,而且一等还是3秒,这意味着什么,3秒才能处理一个请求,My god,我要一个3秒才能处理一个请求的服务器干嘛啊,还是60年代啊:(
如果出现这样的需要等待的情况,应当另起一个线程(推荐使用线程池)去完成这个“长”时间的任务,或者将其它交给一个消息队列,通过发消息的方式将给别人去完成也行,客户端能等,你服务器怎么也能等呢?写出这样的代码,基本上一个服务器也就废了。
这blog我发在个人的心情随笔中,发点牢骚,实在是觉得对于有些人的思路觉得有些不可思议,不吐不快。
分享到:
相关推荐
NULL 博文链接:https://maoyidao.iteye.com/blog/1149015
基于JAVA IO, NIO, Netty, 多线程并发实战源码.zip
第5章介绍了并行程序设计中常见的 些设计模式以及 些典型的并行算法和使用方法,其中包括重要的JavaNIO和AIO的介绍。第6章介绍了 Java 8中为并行计算做的新的改进, 包括并行流、 CompletableFuture、 StampedLock...
从JDK1.5开始又要提供关于线程、并发等新性能的支持,Java应用在游戏等适时领域方面的机会已经成熟,Java在稳定自己中间件地位后,开始蚕食传统C的领域。 本文主要简单介绍NIO的基本原理,在下一篇文章中,将结合...
代码经过压力测试,采用反应器模式,没有第三方框架,实现功能:可以一个线程处理多个请求,也可以加上多线程。处理数据采用的多线程。实现功能:基于HTTP协议,解析请求和拼接响应,基于NIO的非阻塞,线程池,文件...
传统的Java IO是阻塞式的,即当程序进行读写操作时,如果数据没有准备好,线程会阻塞等待,这在高并发场景下会导致线程资源的浪费。而NIO则是非阻塞式的,它允许线程在等待数据准备好的同时,继续执行其他任务,从而...
BIO,NIO,AIO,Netty面试题 35道.pdf Java并发编程最全面试题 123道.pdf Java并发编程面试题 75题.pdf JAVA核心面试知识点整理.pdf Java垃圾收集必备手册.pdf Java虚拟机(JVM)面试题 51道.pdf SpringBoot面试题 30道...
净额从原生Java的Io操作(BIO)到NIO编程,约会NIO高效并发框架——Netty,需要用到Java的基础知识(多线程,网络编程,IO,设计模式尤其是代理模式),介绍了Netty的高级架构设计和核心模块组件,Google上的...
多线程源码JUC以及多线程和高并发 https://blog.csdn.net/u011488009 主要是根据 https://blog.csdn.net/u011488009/category_9678616.html 专栏来讲解的源码,都可以作为高并发的学习,练手用,主要是看这个源码...
24 实现 Java 多线程并发控制框架.mht 25 多线程、多平台环境中的跟踪.mht 26 使用 ConTest 进行多线程单元测试.mht 27 实现非阻塞套接字的一种简单方法.mht 28 基于事件的NIO多线程服务器.mht 29 驯服 Tiger ...
Java异步NIO框架Netty实现高性能高并发无标题笔记 1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨 节点...
多线程&并发面试题 JVM面试题 Mysql面试题 Redis面试题 Memcached面试题 MongoDB面试题 Spring面试题 Spring Boot面试题 Spring Cloud面试题 RabbitMQ面试题 Dubbo 面试题 MyBatis 面试题 ZooKeeper 面试题 数据结构...
JAVANIO原理详解 高并发数据库(Mysql数据库性能优化) 软件质量管控 企业常用框架springMVC基于注解+xml配置方式实现链接 WEB服务器优化之Tomcat7性能调优 JVM概述 Java开发技术之(项目工程的日志管理) 数据库连接池...
要写好一个分布式系统往往是一件比较复杂的事情,特别是使用Java、C++这类不具有并发原语的非函数式编程语言,不仅需要考虑各个线程之间的同步和并发,还要考虑进程以及节点之间的通信和协作。单就通信框架这一层...
5.7并行搜索 5.9并行算法:矩阵乘法 5.10准备好了再通知我:网络nio 5.11读完了再通知我:aio 5.9并行算法:矩阵乘法 5.10准备好了再通知我:网络NIO 5.11读完了再通知我:AIO 5并行模式与算法 实战Java高并发程序...
Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架(当然,也可以提供JAVA 对象的序列化服务、...Socket、JAVA 线程及并发库(java.util.concurrent.*)的知识。
资源内容: Java并行程序基础;Java内存模型和线程安全;并发设计模式;NIO和AIO;锁的优化和注意事项;JDK并发包
• 熟悉Java多线程并发中线程基本方法,线程池,线程生命周期,熟悉Java锁中常见锁分类(乐观/悲观锁、自旋锁、独/共享锁、可重入锁、公平/非公平锁、分段锁、偏向锁,轻/重量级锁)和基本的锁升级策略
Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于 TCP/IP、UDP/IP协议栈的通信...学习本文档,需要你已掌握 JAVA IO、JAVA NIO、JAVA Socket、JAVA 线程及并发库(java.util.concurrent.*)的知识。
16:55:20.677 [main] INFO org.malin.allutils.makefile.ReadFileNameUtil - 获取到 文件名称: 8.NIO和AIO.pdf 16:55:20.677 [main] INFO org.malin.allutils.makefile.ReadFileNameUtil - 获取到 文件名称: 9.锁...