Java NIO 技术要点

本文介绍Java NIO在解决系统运行瓶颈、提高I/O读写效率方面的应用。通过非阻塞技术,采用Reactor模式或观察者模式,实现高效的数据读取。文章详细解释了Selector的工作原理,并提供了一个启动服务器的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:系统运行瓶颈,I/O读写,因为打开一个I/O通道以后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的。


Java NIO解决方案:采用非阻塞技术,采取Reactor模式或者观察者模式,等到内容进来再自动通知,而不必死等,使I/O读写通畅,不堵塞了。

具体原理描述:NIO有一个主要的类selector,它类似一个观察者,只要我们把需要探知的socketChannel告知selector,我们可以安心干其他事情,当有事件发生时,它会消息通知我们,传回一组selectionKey,根据这个key可以获得刚刚注册的socketChannel,然后就可以从这个Channel中读取数据。

Selector的内部原理:实际上是对所有channel做一个轮询访问,一旦发现有事件,比如数据来了,它就会通知报告,交出一把钥匙。

以下是测试代码

/**
	 * Start server
	 * 
	 * @throws IOException
	 */
	public void startServer() throws IOException {
		int channels = 0;
		int nKeys = 0;
//		int currentSelector = 0;
		
		// Use selector 
		Selector selector = Selector.open();
		
		ServerSocketChannel ssc = ServerSocketChannel.open();
		InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 9000);
		
		// Bind address
		ssc.socket().bind(address);
		
		// Non-blocking model
		ssc.configureBlocking(false);
		
		// Register
		SelectionKey sk = ssc.register(selector, SelectionKey.OP_ACCEPT);
		printKeyInfo(sk);
		
		// For each
		while (true) {
			debug("Starting select...");
			
			// Some thing happened. return a set of keys which channels are ready for I/O
			nKeys = selector.select();
			
			if(nKeys > 0) {
				debug("Number of keys after select operation: " + nKeys);
				
				//Selector传回一组SelectionKeys
				Set<SelectionKey> selectedKeys = selector.selectedKeys();
				Iterator<SelectionKey> i = selectedKeys.iterator();
				while(i.hasNext()) {
					sk = (SelectionKey) i.next();
					printKeyInfo(sk);
					
					debug("Nr Keys in selector: " +selector.keys().size());
					
					// Remove
					i.remove();
					
					if(sk.isAcceptable()) {
						Socket socket = ((ServerSocketChannel)sk.channel()).accept().socket();
						SocketChannel sc = socket.getChannel();
						
						sc.configureBlocking(false);
						sc.register(selector, SelectionKey.OP_READ |SelectionKey.OP_WRITE);
						System.out.println(++channels);
					} else {
						debug("Channel not acceptable");
					}
				}
			} else {
				 debug("Select finished without any keys.");
			}
		}
	}

	/**
	 * Debug
	 * 
	 * @param str
	 */
	private static void debug(String str) {
		System.out.println("NIO Test: " + str);
	}
	
	/**
	 * Print key info
	 * 
	 * @param sk
	 */
	private static void printKeyInfo(SelectionKey sk) {
		StringBuffer sb = new StringBuffer();

		sb.append("Att: " + (sk.attachment() == null ? "no" : "yes"));
		sb.append(", Read: " + sk.isReadable());
		sb.append(", Acpt: " + sk.isAcceptable());
		sb.append(", Cnct: " + sk.isConnectable());
		sb.append(", Wrt: " + sk.isWritable());
		sb.append(", Valid: " + sk.isValid());
		sb.append(", Ops: " + sk.interestOps());
		debug(sb.toString());
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值