`
Aga
  • 浏览: 218642 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

nio与io的比较

    博客分类:
  • J2SE
阅读更多
nio是new io的简称,从jdk1.4就被引入了。现在的jdk已经到了1.6了,可以说不是什么新东西了。但其中的一些思想值得我来研究。这两天,我研究了下其中的套接字部分,有一些心得,在此分享。
首先先分析下:为什么要nio套接字?
nio的主要作用就是用来解决速度差异的。举个例子:计算机处理的速度,和用户按键盘的速度。这两者的速度相差悬殊。如果按照经典的方法:一个用户设定一个线程,专门等待用户的输入,无形中就造成了严重的资源浪费:每一个线程都需要珍贵的cpu时间片,由于速度差异造成了在这个交互线程中的cpu都用来等待。
nio套接字是怎么做到的?
其实,其中的思想很简单:轮询。一个线程轮询多个input;传统的方式是:有n个客户端就要有n个服务线程+一个监听线程,现在采取这种凡是,可以仅仅使用1个线程来代替n个服务线程以此来解决。
具体应用例子:
在ftp的控制连接中,因为只有少量的字符命令进行传输,所以可以考虑利用这种轮询的方式实现,以节省资源。
具体见例子。
package com.cxz.io;   
  
import java.io.BufferedReader;   
import java.io.IOException;   
import java.io.InputStreamReader;   
import java.net.ServerSocket;   
import java.net.Socket;   
import java.util.HashMap;   
import java.util.Map;   
import java.util.Collections;   
  
public class IoEchoServer implements Runnable {   
  
    // ThreadLocal<Socket> localSocket = new ThreadLocal<Socket>();   
    Map<String, Socket> socketMap = Collections   
            .synchronizedMap(new HashMap<String, Socket>());   
  
    int threadCounter = 0;   
  
    synchronized private int getCounter() {   
        return threadCounter++;   
    }   
  
    public IoEchoServer() throws IOException {   
        ServerSocket server = new ServerSocket(1984);   
        while (true) {   
            Socket socket = server.accept();   
            // happened in the main thread.   
            // localSocket.set(socket);   
            String threadName = "---Thread" + getCounter() + "---";   
            socketMap.put(threadName, socket);   
            this.start(threadName);   
        }   
    }   
  
    /**  
     * @param args  
     * @throws IOException  
     */  
    public static void main(String[] args) throws IOException {   
        new IoEchoServer();   
    }   
  
    public void run() {   
        try {   
            Socket socket = socketMap.get(Thread.currentThread().getName());   
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));   
            //PrintWriter out = new PrintWriter(socket.getOutputStream());   
            String buffer = null;   
            while(!"END".equals(buffer)){   
                buffer = in.readLine();   
                System.out.println(buffer);   
            }   
            in.close();   
            socket.close();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
    }   
  
    public void start(String threadName) {   
        new Thread(this, threadName).start();   
    }   
  
}  


下面这个例子采取了nio方式实现,虽然还是有阻塞部分,但是与上一个相比,效率已经大幅提高。仅仅阻塞到一个监听线程中。
package com.cxz.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set;

public class NioEchoServer {

	private static Selector roller = null;

	private static final int port = 8080;

	private static NioEchoServer instance = null;

	private ThreadLocal<StringBuffer> stringLocal = new ThreadLocal<StringBuffer>();

	private NioEchoServer() throws IOException {
		ServerSocketChannel serverChannel = ServerSocketChannel.open();
		serverChannel.socket().bind(new InetSocketAddress(port));
		serverChannel.configureBlocking(false);
		serverChannel.register(roller, SelectionKey.OP_ACCEPT);
	}

	public synchronized static NioEchoServer getInstance() throws IOException {
		if (instance == null) {
			roller = Selector.open();
			instance = new NioEchoServer();
		}
		return instance;
	}

	public void start() throws IOException {
		int keyAdded = 0;
		while ((keyAdded = roller.select()) > 0) {
			Set<SelectionKey> keySets = roller.selectedKeys();
			Iterator iter = keySets.iterator();
			while (iter.hasNext()) {
				SelectionKey key = (SelectionKey) iter.next();
				iter.remove();
				actionHandler(key);
			}
		}
	}

	public void actionHandler(SelectionKey key) throws IOException {
		if (key.isAcceptable()) {
			ServerSocketChannel serverChannel = (ServerSocketChannel) key
					.channel();
			SocketChannel socketChannel = serverChannel.accept();
			socketChannel.configureBlocking(false);
			socketChannel.register(roller, SelectionKey.OP_READ);
		} else if (key.isReadable()) {
			ByteBuffer buffer = ByteBuffer.allocate(16);
			SocketChannel socketChannel = (SocketChannel) key.channel();
			socketChannel.read(buffer);
			buffer.flip();
			String temp = decode(buffer);
			StringBuffer strBuffer = stringLocal.get();
			if (strBuffer == null) {
				strBuffer = new StringBuffer();
			}

			strBuffer.append(temp);

			if (temp.equals("\r\n")) {
				System.out.println(strBuffer.toString());
				strBuffer = null;
			}
			stringLocal.set(strBuffer);
		}
	}

	public String decode(ByteBuffer buffer) {
		Charset charset = null;
		CharsetDecoder decoder = null;
		CharBuffer charBuffer = null;
		try {
			charset = Charset.forName("UTF-8");
			decoder = charset.newDecoder();
			charBuffer = decoder.decode(buffer);
			return charBuffer.toString();
		} catch (Exception ex) {
			ex.printStackTrace();
			return "";
		}
	}

	public static void main(String[] args) {
		try {
			NioEchoServer.getInstance().start();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
6
2
分享到:
评论
7 楼 flychao88 2015-03-06  
nothingismao 写道
623deyingxiong 写道
wwj85523 写道

看完后我迷糊了,
IO一样可以一个线程管理多个socket啊
貌似这不是NIO和IO的差别

是啊,一个线程负责监听,有请求过来就拉过来一个工作线程处理请求。这跟NIO的模式有区别吗?
另外,NIO有一个while循环不断地轮询各个通道,这难道就是非阻塞?


第1.NIO中Selector负责监听,对于过来的请求可以不用另外起启动线程去除了,而IO中则必须为每一个连接去创建线程处理.这个有很大区别.而且在IO中创建的线程很多时候是处于阻塞状态,这时候CPU会进行时间片切换不同的线程造成资源的损耗.
第2.个人觉得NIO中while判断是否有事件是通过事件请求的机制实现的.如果底层还是给每个连接创建一个线程的话NIO没任何意义.所以实际NIO中用于处理连接的线程可以只有一个.



楼主说的每个IO必须要起一个线程处理,这是采用线程池的方式,也可以不用另外起线程。
我认为楼主没有说清楚NIO和IO的本质区别,从字面上的意思,似乎两者并没有太大的区别,从我个人感觉NIO和IO有本质区别,是因为NIO是非阻塞,这个非阻塞怎么理解,就是当NIO的处理逻辑出现阻塞的时候,NIO会继续接收新的请求来处理,待上一次阻塞的逻辑改变了状态后,NIO再继续回来执行,如果是IO的话,不管起多少个线程,遇到阻塞则会一直等待下去,不会动态的切换。
6 楼 李冰冰 2014-10-13  
如果NIO单个线程处理业务逻辑,那么如果这个业务逻辑非常耗时,此时其余的线程其实是都需要等待这个主逻辑处理结束之后,才会重新调用select()函数,进行取数据处理,如果这样,为何不像IO那样一个请求开辟一个线程来进行业务处理,而不会因为业务处理负责,导致其他的请求数据造成延迟,请楼主给予解释,谢谢。
5 楼 wj_126mail 2014-03-29  
IO是一个连接就创建一个线程来处理;

NIO是一个线程在处理所有的SCOKET。
4 楼 nothingismao 2013-11-27  
623deyingxiong 写道
wwj85523 写道

看完后我迷糊了,
IO一样可以一个线程管理多个socket啊
貌似这不是NIO和IO的差别

是啊,一个线程负责监听,有请求过来就拉过来一个工作线程处理请求。这跟NIO的模式有区别吗?
另外,NIO有一个while循环不断地轮询各个通道,这难道就是非阻塞?


第1.NIO中Selector负责监听,对于过来的请求可以不用另外起启动线程去除了,而IO中则必须为每一个连接去创建线程处理.这个有很大区别.而且在IO中创建的线程很多时候是处于阻塞状态,这时候CPU会进行时间片切换不同的线程造成资源的损耗.
第2.个人觉得NIO中while判断是否有事件是通过事件请求的机制实现的.如果底层还是给每个连接创建一个线程的话NIO没任何意义.所以实际NIO中用于处理连接的线程可以只有一个.
3 楼 623deyingxiong 2013-01-12  
wwj85523 写道

看完后我迷糊了,
IO一样可以一个线程管理多个socket啊
貌似这不是NIO和IO的差别

是啊,一个线程负责监听,有请求过来就拉过来一个工作线程处理请求。这跟NIO的模式有区别吗?
另外,NIO有一个while循环不断地轮询各个通道,这难道就是非阻塞?
2 楼 wwj85523 2011-04-13  

看完后我迷糊了,
IO一样可以一个线程管理多个socket啊
貌似这不是NIO和IO的差别
1 楼 wj_126mail 2010-07-21  
NIO比IO可以提高效率,但为什么可以提高效率,以及是怎样提高效率的,不一定都明白,LZ讲的明白的很,学习过后,表示感谢!

相关推荐

    Java NIO与IO性能对比分析.pdf

    本文将分析Java NIO与Java IO在性能上的对比,并尝试找出性能差异的原因,以及探讨哪种编程模型更适合高并发的应用场景。 Java IO模型是一种阻塞型I/O模型,在数据的读写过程中,如果线程在等待数据,将会一直被挂...

    java nio与io性能测试

    Java NIO(New IO)是Java 1.4引入的一个新模块,它是对传统IO(Input/Output)的扩展,提供...而`CopyFile.java`和`io与nio性能测试.txt`就是这种比较的关键工具,它们可以帮助我们理解这两种技术在实际操作中的表现。

    Java_NIO与IO的区别和比较.doc

    与传统IO流不同,通道可以同时进行读写操作,且支持非阻塞模式。 4. **Selector**:Selector是NIO的核心组件,它允许单个线程监控多个通道的事件(如连接请求、数据到达等)。通过注册通道到Selector并设置感兴趣的...

    Java NIO与IO的区别和比较.pdf

    ### Java NIO与IO的区别和比较 #### 引言 随着网络技术的飞速发展,企业和个人对网络应用程序的性能要求日益提高。特别是在高并发环境下,服务器需要处理来自数百乃至数千个客户端的同时连接请求,这使得传统的...

    Java NIO与IO性能对比分析.zip

    本篇将深入探讨Java NIO与IO的性能对比,帮助开发者更好地理解两者之间的差异,并在实际项目中做出合适的选择。 首先,我们来看Java传统的IO模型。IO基于流(Stream)进行数据传输,分为字节流和字符流两大类,提供...

    NIO与传统IO代码区别实例

    总的来说,理解IO与NIO的区别,以及它们在不同场景下的优缺点,对于提升Java服务器开发的性能和效率至关重要。NIO尤其适用于需要处理大量并发连接的网络服务,如聊天服务器、游戏服务器等。希望这个简要的介绍能帮助...

    Java-NIO与IO的区别和比较.doc

    Java NIO(New Input/Output)是Java标准库在J2SE 1.4及后续版本中引入的一个重要更新,它的出现是为了改进传统的IO模型,提高I/O操作的效率和并发性。NIO的主要特点包括非阻塞I/O、字符转换、缓冲区以及通道等。 1...

    IO和NIO区别

    IO和NIO区别 Java 中的 IO 和 NIO 是两个不同的输入/输出机制,它们之间有许多区别。下面我们将详细讲解 IO 和 NIO 的区别。 1. 数据处理方式 标准 IO 以流的方式处理数据,也就是说数据是以流的形式传输的,而 ...

    JavaNIO与IO的区别和比较.pdf

    传统的IO操作通常直接在流与数据源之间进行,而NIO则引入了缓冲区,数据先被写入缓冲区,再由缓冲区批量读写到通道或文件中。这样减少了数据拷贝次数,提高了效率。Buffer提供了诸如容量、限制、位置等概念,方便了...

    Java.nio 与Java.io比较

    在探讨Java.nio与Java.io之间的比较时,我们首先需要理解这两个包在Java编程语言中的核心作用和它们各自的优势。Java.io和Java.nio是Java中处理输入/输出操作的两个主要框架,它们各自拥有独特的特性和应用场景。 #...

    Java IO_NIO

    Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的基础框架,它提供了丰富的类库,使得程序能够与各种设备、文件、...理解和掌握Java IO与NIO的使用,对于提升Java应用程序的性能和可扩展性至关重要。

    Nio和Io的详细描述.docx

    - **NIO与IO对比**:讨论NIO和传统IO在性能、并发性和复杂性上的差异。 - **Path**:表示文件系统路径的对象。 - **Files**:提供与文件系统交互的工具类。 - **异步文件通道(AsynchronousFileChannel)**:支持...

    Java IO与NIO:深入理解与实践指南

    Java IO和NIO提供了两种不同的I/O处理方式,各有优势和适用场景。IO适用于简单的I/O操作,而NIO则适合于需要高性能和高并发的应用。了解这两种I/O处理方式的区别和特点,可以帮助开发者根据具体的应用需求选择合适的...

    java io 与java nio区别

    在深入探讨Java IO与Java NIO之间的区别之前,我们先简单回顾一下这两种I/O模型的基本概念。 #### 1. Java IO(Blocking IO) Java IO,也称为传统的阻塞式IO或同步阻塞式IO,是Java早期版本中的主要I/O处理方式。...

    JavaNIO浅析IO模型Java开发Java经验技巧共1

    与传统的IO模型相比,NIO具有非阻塞、多路复用等优点,尤其适用于高并发、低延迟的网络应用。本文将深入浅出地探讨Java NIO的基本概念、主要组件以及它如何改进了传统的IO模型。 一、Java NIO概述 在Java传统的IO...

    NIO和传统IO比较.rar

    传统的Java IO API自Java 1.0版本起就已经存在,而NIO(New IO)则是在Java 1.4版本引入的新特性。两者在处理I/O操作时有显著的区别,这些差异对于理解和优化应用程序性能至关重要。 1. **模型差异** - **传统IO**...

    自己封装的IO核NIO

    总的来说,"自己封装的IO核NIO"项目通过封装Java的IO和NIO,提供了更高效、易用的网络通信工具,特别是对于需要频繁与服务器交互的应用,如微信开发,能显著提升开发体验。而其中的HTTP客户端则进一步简化了HTTP请求...

    NIO和IO中文概述文档.docx

    NIO与传统的IO(-blocking IO)的主要区别在于处理I/O事件的方式以及对并发的处理能力。 传统的Java IO基于流(Stream)模型,数据被读取或写入时,程序会一直阻塞直到操作完成。而NIO则引入了通道(Channel)和缓冲区...

Global site tag (gtag.js) - Google Analytics