Java NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的。
Java NIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。
Java NIO出现不只是一个技术性能的提高,你会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。
图 1 类结构图
package cn.chenkangxian.nioconcurrent;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
import java.util.List;
/**
* @Project: testNio
*
* @Author: chenkangxian
*
* @Annotation: 使用线程池来处理大量channel并发
*
* @Date:2011-7-5
*
* @Copyright: 2011 chenkangxian, All rights reserved.
*
*/
public class SelectSocketsThreadPool extends SelectSockets {
private static final int MAX_THREADS = 5;
private ThreadPool pool = new ThreadPool(MAX_THREADS);
/**
* 从socket中读数据
*/
protected void readDataFromSocket(SelectionKey key) throws Exception {
WorkerThread worker = pool.getWorker();
if (worker == null) {
return;
}
worker.serviceChannel(key);
}
/**
*
* @Project: concurrentnio
*
* @Author: chenkangxian
*
* @Annotation:线程池
*
* @Date:2011-7-20
*
* @Copyright: 2011 chenkangxian, All rights reserved.
*
*/
private class ThreadPool {
List idle = new LinkedList();
/**
* 线程池初始化
*
* @param poolSize 线程池大小
*/
ThreadPool(int poolSize) {
for (int i = 0; i < poolSize; i++) {
WorkerThread thread = new WorkerThread(this);
thread.setName("Worker" + (i + 1));
thread.start();
idle.add(thread);
}
}
/**
* 获得工作线程
*
* Author: chenkangxian
*
* Last Modification Time: 2011-7-20
*
* @return
*/
WorkerThread getWorker() {
WorkerThread worker = null;
synchronized (idle) {
if (idle.size() > 0) {
worker = (WorkerThread) idle.remove(0);
}
}
return (worker);
}
/**
* 送回工作线程
*
* Author: chenkangxian
*
* Last Modification Time: 2011-7-20
*
* @param worker
*/
void returnWorker(WorkerThread worker) {
synchronized (idle) {
idle.add(worker);
}
}
}
private class WorkerThread extends Thread {
private ByteBuffer buffer = ByteBuffer.allocate(1024);
private ThreadPool pool;
private SelectionKey key;
WorkerThread(ThreadPool pool) {
this.pool = pool;
}
public synchronized void run() {
System.out.println(this.getName() + " is ready");
while (true) {
try {
this.wait();//等待被notify
} catch (InterruptedException e) {
e.printStackTrace();
this.interrupt();
}
if (key == null) {//直到有key
continue;
}
System.out.println(this.getName() + " has been awakened");
try {
drainChannel(key);
} catch (Exception e) {
System.out.println("Caught '" + e + "' closing channel");
try {
key.channel().close();
} catch (IOException ex) {
ex.printStackTrace();
}
key.selector().wakeup();
}
key = null;
this.pool.returnWorker(this);
}
}
synchronized void serviceChannel(SelectionKey key) {
this.key = key;
//消除读的关注
key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
this.notify();
}
void drainChannel(SelectionKey key) throws Exception {
SocketChannel channel = (SocketChannel) key.channel();
int count;
buffer.clear();
while ((count = channel.read(buffer)) > 0) {
buffer.flip();
while (buffer.hasRemaining()) {
channel.write(buffer);
}
buffer.clear();
}
if (count < 0) {
channel.close();
return;
}
//重新开始关注读事件
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
key.selector().wakeup();
}
}
public static void main(String[] args) throws Exception {
new SelectSocketsThreadPool().go(args);
}
}
package cn.chenkangxian.nioconcurrent;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
*
* @Project: concurrentnio
*
* @Author: chenkangxian
*
* @Annotation:
*
* @Date:2011-7-11
*
* @Copyright: 2011 chenkangxian, All rights reserved.
*
*/
public class SelectSockets {
public static int PORT_NUMBER = 1234;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
public static void main(String[] args) throws Exception {
new SelectSockets().go(args);
}
public void go(String[] args) throws Exception{
int port = PORT_NUMBER;
// if(args.length > 0){
// port = Integer.parseInt(args[0]);
// }
// System.out.println("Listening on port " + port);
ServerSocketChannel serverChannel = ServerSocketChannel.open();
ServerSocket serverSocket = serverChannel.socket();
Selector selector = Selector.open();
serverSocket.bind(new InetSocketAddress(port));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true){
int n = selector.select(); //没有轮询,单个selector
if(n == 0){
continue;
}
Iterator it = selector.selectedKeys().iterator();
while(it.hasNext()){
SelectionKey key = (SelectionKey)it.next();
if(key.isAcceptable()){
ServerSocketChannel server =
(ServerSocketChannel)key.channel();
SocketChannel channel = server.accept();
registerChannel(selector,channel
,SelectionKey.OP_READ);
sayHello(channel);
}
if(key.isReadable()){
readDataFromSocket(key);
}
it.remove();
}
}
}
/**
* 在selector上注册channel,并设置interest
*
* Author: chenkangxian
*
* Last Modification Time: 2011-7-11
*
* @param selector 选择器
*
* @param channel 通道
*
* @param ops interest
*
* @throws Exception
*/
protected void registerChannel(Selector selector,
SelectableChannel channel, int ops) throws Exception{
if(channel == null){
return ;
}
channel.configureBlocking(false);
channel.register(selector, ops);
}
/**
* 处理有可用数据的通道
*
* Author: chenkangxian
*
* Last Modification Time: 2011-7-11
*
* @param key 可用通道对应的key
*
* @throws Exception
*/
protected void readDataFromSocket(SelectionKey key) throws Exception{
SocketChannel socketChannel = (SocketChannel)key.channel();
int count;
buffer.clear(); //Empty buffer
while((count = socketChannel.read(buffer)) > 0){
buffer.flip();
while(buffer.hasRemaining()){
socketChannel.write(buffer);
}
buffer.clear();
}
if(count < 0){
socketChannel.close();
}
}
/**
* 打招呼
*
* Author: chenkangxian
*
* Last Modification Time: 2011-7-11
*
* @param channel 客户端channel
*
* @throws Exception
*/
private void sayHello(SocketChannel channel) throws Exception{
buffer.clear();
buffer.put("Hello 哈罗! \r\n".getBytes());
buffer.flip();
channel.write(buffer);
}
}
- 大小: 28.7 KB
分享到:
相关推荐
NIO的核心组件是Selector,它是一个监管多个Channel的多路复用器,能够检测一个或多个Channel是否处于就绪状态,即检查Channel是否有I/O操作可执行。这种模式使得仅需要一个或几个线程就能管理多个Channel,大大降低...
NIO的核心概念包括Channel(通道)、Selector(选择器)和Buffer(缓冲区)。Channel类似于BIO中的流,但更具体,可以类比为实际的交通方式,如汽车或高铁,它提供了读写数据的能力。Selector扮演调度者的角色,能够...
通过分析这个NIO项目源码,你可以学习到如何在实际项目中应用NIO技术,理解其设计模式和优化策略,对于提升Java网络编程的能力大有裨益。深入研究NIO的细节,有助于你在开发高效、高并发的服务时做出明智的选择。
NIO的主要特点是采用面向缓冲区、通道和选择器的模式,而不是传统的字节流方式。这种方式不仅提高了数据处理速度,而且通过非阻塞通信机制,使得单个线程能够管理更多的连接,极大地优化了资源利用效率。 #### Java...
NIO的核心组件包括通道(Channels)、选择器(Selectors)和缓冲区(Buffers)。在Java NIO中,Socket通信可以采用非阻塞模式,允许一个线程处理多个客户端连接,这对于高并发的网络应用尤其有益。 在给定的示例中...
NIO与传统的 Blocking I/O(阻塞I/O)模式相比,最大的区别在于,NIO不会在等待数据时阻塞线程,而是采用回调或轮询的方式,这样可以更好地利用系统资源,提高并发处理能力。 NIO的核心组件包括通道(Channel)、...
Java NIO的核心组件主要包括通道(Channels)、缓冲区(Buffers)和选择器(Selectors): - **通道(Channels)**:通道是数据传输的途径,类似于传统IO中的流。Java NIO提供了多种通道,如FileChannel用于文件...
此外,`java.nio.channels.Selector.select()`方法的实现也非常重要,它会阻塞直到至少有一个通道准备就绪,然后返回就绪通道的数量。 对于大数据处理,NIO的一个典型应用场景是高并发的网络服务器,例如基于NIO的...
Reactor模式和NIO是两种在网络编程中广泛使用的并发处理技术。Reactor模式是一种事件驱动的设计模式,主要用于解决高并发场景下的系统设计问题,而Java的NIO(Non-blocking Input/Output,非阻塞I/O)是Java平台提供...
- **缓冲区(Buffers)**:NIO中的数据操作都在缓冲区上进行,这是NIO的主要特性之一,缓冲区提供了更高效的数据存取方式。 - **选择器(Selectors)**:选择器允许单个线程监视多个通道,当通道准备好进行读写...
3. **Reactor模式**:在NIO中,Reactor模式是一种处理多个客户端连接的并发设计模式。它通过一个线程来监听和接受新的连接,然后分派事件到相应的处理器。相比于传统的多线程模型,Reactor模式可以更有效地管理大量...
- **选择器使用**:通过Selector监听多个通道的就绪状态,实现多路复用,提高程序并发性能。 - **非阻塞I/O**:展示如何使用非阻塞模式避免线程被长时间阻塞,提高系统资源利用率。 这个Demo将帮助你理解如何在实际...
**NIO非阻塞模式**:相比之下,NIO采用了非阻塞模式,即当没有数据可读时,`read()`方法不会阻塞,而是立即返回。这意味着应用程序可以同时处理多个输入/输出操作,而不需要为每个操作分配一个独立的线程。这样的...
而NIO则采用了非阻塞模式,允许程序在等待数据准备就绪的过程中去做其他事情,提高了程序的效率和并发性。 **NIO的核心组件:** 1. **Channel(通道)**:Channel是数据传输的双向管道,可以同时进行读写操作。例如...
4. **多路复用器模式(Multiplexing)**:Java NIO的这种模式使得服务器可以处理成千上万个并发连接,而不必为每个连接创建单独的线程,避免了线程上下文切换的开销,提升了性能。在高并发场景下,如Web服务器、聊天...
选择器通过调用`select()`方法来获取准备就绪的通道,并且可以选择性地处理这些通道。 4. **非阻塞I/O**: 在传统的BIO模型中,如果一个线程正在进行I/O操作时被阻塞,其他线程也无法进行任何操作。而NIO的非阻塞...
Java NIO(New IO)是Java平台提供的一种新的IO操作模式,它首次出现在Java 1.4版本中,并在后续版本中不断完善。Java NIO 的设计目的是为了克服传统Java IO API在面对大量并发连接时存在的性能瓶颈。 ##### 使用...
NIO的核心概念和机制包括阻塞和非阻塞、同步和异步以及IO模型和选择器 Selector。 首先,阻塞与非阻塞关注的是进程访问数据时,数据是否准备就绪的处理方式。在阻塞模式下,当请求的数据没有准备好时,进程会停下来...
而NIO则是采用非阻塞模式,当数据未准备好时,程序不会等待,而是继续执行其他任务,从而提高了程序的执行效率。 NIO的核心组件包括通道(Channel)、缓冲区(Buffer)和选择器(Selector)。接下来,我们将详细...
NIO的主要特点是面向缓冲区,非阻塞I/O,以及选择器,这些特性使得NIO在处理大量并发连接时表现出更高的效率。在本篇文章中,我们将深入探讨Java NIO如何读取文件。 一、NIO的基本概念 1. 缓冲区(Buffer):NIO的...