Java IO与NIO的真正区别是什么?
我非常喜欢JavaNIO,我真的很想将JavaNIO应用到我当前的系统中,但是当我创建这些示例应用程序来比较JavaIO和NIO时,这让我非常失望 这是我的两个示例(我没有列出所有的源代码) Java IOJava IO与NIO的真正区别是什么?,java,networking,io,netty,nio,Java,Networking,Io,Netty,Nio,我非常喜欢JavaNIO,我真的很想将JavaNIO应用到我当前的系统中,但是当我创建这些示例应用程序来比较JavaIO和NIO时,这让我非常失望 这是我的两个示例(我没有列出所有的源代码) Java IO public class BlockingServerClient { private static final Logger log = Logger.getLogger(BlockingServerClient.class.getName()); static fin
public class BlockingServerClient {
private static final Logger log = Logger.getLogger(BlockingServerClient.class.getName());
static final ExecutorService service = Executors.newCachedThreadPool();
public static void main(String[] args) throws InterruptedException {
int port = Integer.parseInt(args[0]);
BlockingServerClient server = new BlockingServerClient();
Server sr = server.new Server(port);
service.submit(sr);
}
private class Server implements Runnable {
.....
public void run() {
ServerSocket ss = null;
try {
ss = new ServerSocket(localPort);
log.info("Server socket bound to " + localPort);
while (true) {
Socket client = ss.accept();
log.info("Accepted connection from " + client.getRemoteSocketAddress());
service.submit(new SocketClient(client));
}
} catch (IOException e) {
log.log(Level.SEVERE, "Server error", e);
} finally {
.....
}
}
}
private class SocketClient implements Runnable {
.....
public void run() {
InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress();
socketInfo = String.format("%s:%s", addr.getHostName(), addr.getPort());
log.info("Start reading data from " + socketInfo);
try {
in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String input;
while ((input = in.readLine()) != null) {
log.info(String.format("[%s] %s", socketInfo, input));
log.info("Socket " + socketInfo + " thread sleep 4s");
TimeUnit.SECONDS.sleep(4);
}
} catch (Exception ex) {
log.log(Level.SEVERE, "Socket error", ex);
} finally {
.....
}
}
}
}
Java NIO
public class NonBlockingServerClient {
private static final Logger log = Logger.getLogger(NonBlockingServerClient.class.getName());
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
NonBlockingServerClient sc = new NonBlockingServerClient();
Server server = sc.new Server(port, boss, worker);
server.run();
} catch (Exception e) {
log.log(Level.SEVERE, "Error", e);
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
private class Server {
.....
public void run() {
log.info("Start Server bootstrap");
ServerBootstrap b = new ServerBootstrap();
b.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipe = ch.pipeline();
pipe.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipe.addLast(new StringDecoder());
pipe.addLast(new ClientHandler());
}
});
ChannelFuture future = null;
try {
future = b.bind(port).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.log(Level.SEVERE, "Server binding error", e);
future.channel().close();
}
}
}
private class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg)
throws Exception {
log.info(String.format("[%s] %s", ctx.channel().remoteAddress(), msg));
log.info(ctx.channel().remoteAddress() + " sleep 4s");
TimeUnit.SECONDS.sleep(4);
}
}
}
公共类非阻塞服务器客户端{
私有静态最终记录器log=Logger.getLogger(NonBlockingServerClient.class.getName());
公共静态void main(字符串[]args){
int port=Integer.parseInt(args[0]);
EventLoopGroup boss=新的NioEventLoopGroup();
EventLoopGroup worker=new NioEventLoopGroup();
试一试{
NonBlockingServerClient sc=新的NonBlockingServerClient();
服务器服务器=sc.new服务器(端口、boss、工作者);
server.run();
}捕获(例外e){
log.log(严重级别,“错误”,e);
}最后{
老板。优雅地关机();
工人。优雅地关机();
}
}
私有类服务器{
.....
公开募捐{
log.info(“启动服务器引导”);
ServerBootstrap b=新的ServerBootstrap();
b、 组(老板、工人)
.channel(NioServerSocketChannel.class)
.childHandler(新的通道初始值设定项(){
@凌驾
受保护的无效初始化通道(通道ch)引发异常{
ChannelPipeline管道=通道管道();
addLast(新的DelimiterBasedFrameDecoder(8192,Delimiters.lineDelimiter());
addLast(新的StringDecoder());
addLast(新ClientHandler());
}
});
ChannelFuture=null;
试一试{
future=b.bind(port.sync();
future.channel().closeFuture().sync();
}捕捉(中断异常e){
log.log(严重级别,“服务器绑定错误”,e);
future.channel().close();
}
}
}
私有类ClientHandler扩展了SimpleChannelInboundHandler{
@凌驾
受保护的无效channelRead0(ChannelHandlerContext ctx,字符串msg)
抛出异常{
log.info(String.format(“[%s]%s”,ctx.channel().remoteAddress(),msg));
log.info(ctx.channel().remoteAddress()+“sleep 4s”);
时间单位。秒。睡眠(4);
}
}
}
客户
public class Client {
private static final Logger log = Logger.getLogger(Client.class.getName());
public static void main(String[] args) throws InterruptedException {
int port = Integer.parseInt(args[0]);
for (int i = 0; i < 10; i++) {
Client cl = new Client("localhost", port);
cl.start();
TimeUnit.MILLISECONDS.sleep(500);
}
}
String host;
int port;
public Client(String host, int port) {
this.host = host;
this.port =port;
}
public void start() {
log.info("Start client running");
Socket socket = null;
String info = "";
try {
socket = new Socket(host, port);
InetSocketAddress addr = (InetSocketAddress) socket.getLocalSocketAddress();
info = String.format("%s:%s", addr.getHostName(), addr.getPort());
int count = 10;
OutputStream out = socket.getOutputStream();
while (count > 0) {
String outStr = "Output-" + count + "\n";
out.write(outStr.getBytes());
out.flush();
count--;
}
out.write((info + "-Finish sending").getBytes());
out.flush();
} catch (Exception e) {
log.log(Level.SEVERE, "Client error", e);
} finally {
try {
socket.close();
log.info(info + "-Client close");
} catch (IOException e) {
log.log(Level.SEVERE, "Closing client error", e);
}
}
}
}
公共类客户端{
私有静态最终记录器log=Logger.getLogger(Client.class.getName());
公共静态void main(字符串[]args)引发InterruptedException{
int port=Integer.parseInt(args[0]);
对于(int i=0;i<10;i++){
客户端cl=新客户端(“本地主机”,端口);
cl.start();
时间单位。毫秒。睡眠(500);
}
}
字符串主机;
国际港口;
公共客户端(字符串主机,int端口){
this.host=host;
this.port=端口;
}
公开作废开始(){
log.info(“启动客户端运行”);
套接字=空;
字符串信息=”;
试一试{
套接字=新套接字(主机、端口);
InetSocketAddress addr=(InetSocketAddress)socket.getLocalSocketAddress();
info=String.format(“%s:%s”,addr.getHostName(),addr.getPort());
整数计数=10;
OutputStream out=socket.getOutputStream();
而(计数>0){
字符串outStr=“输出-”+count+“\n”;
out.write(outsr.getBytes());
out.flush();
计数--;
}
out.write((info+“-Finish sending”).getBytes();
out.flush();
}捕获(例外e){
log.log(严重级别,“客户端错误”,e);
}最后{
试一试{
socket.close();
log.info(info+“-客户端关闭”);
}捕获(IOE异常){
log.log(严重级别,“关闭客户端错误”,e);
}
}
}
}
客户端运行时将创建10个客户端连接到服务器。在我运行和监视了几次之后,我发现JavaIO和NIO之间没有什么不同
如果将客户机的数量更改为500,我发现JavaIO确实创建了500个线程,但是数据的消耗非常快。相比之下,javanio应用程序的线程比其他应用程序少得多,但数据消耗速度慢,完成所有工作需要更长的时间
那么,JavaNIO的真正好处是什么呢?创建更少的线程以节省内存,但性能较慢
或者,我可能做得不对。您注意到的速度差异是因为两个测试用例中都出现了4s睡眠 在非NIO的情况下,每个请求有一个线程,睡眠4秒只会阻塞这一个请求。然而,在NIO的情况下,工作线程的数量要少得多,它会阻止该请求以及等待在该线程上运行的所有其他请求 这就引出了一个问题,为什么我们希望在NIO方法中使用更少的线程?答案是可伸缩性。现代操作系统存在一个与网络IO上阻塞的线程数相关的扩展问题。有关更多详细信息,请参阅问题 总的来说,我确实发现NIO的速度更快,或者至少在以下情况下它有可能更快:
select()
内部系统调用。我不确定,为什么我们比较线程阻塞IO和线程NIO。