Java NIO之选择就绪模式

开发 后端
Java NIO出现不只是一个技术性能的提高,你会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。

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); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.

 

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); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.

原文链接:http://chenkangxian.iteye.com/blog/1288246

【编辑推荐】

  1. Java代码规范那些事
  2. Java效率真的很低吗?Android为何要采用?
  3. 漫谈Java开源5年:自由但带着枷锁
  4. Google提供JavaScript库以简化Google API的调用
  5. 解析Java语言11个主要特性
责任编辑:林师授 来源: chenkangxian的博客
相关推荐

2011-11-25 09:56:16

H3C

2011-12-07 17:17:02

JavaNIO

2015-11-09 19:03:04

戴尔云计算

2015-11-09 17:28:12

戴尔云计算

2022-12-08 09:10:11

I/O模型Java

2012-05-16 17:15:04

Java设计模式

2011-11-17 16:03:05

Java工厂模式Clojure

2012-05-16 17:22:11

Java设计模式

2011-12-15 09:55:47

javanio

2011-12-07 14:57:44

JavaNIO

2011-12-15 11:19:08

JavaNIO

2011-12-15 09:40:06

Javanio

2013-05-23 15:59:00

线程池

2023-07-28 08:23:05

选择器Java NIO

2011-04-06 11:41:25

Java动态代理

2011-12-07 14:41:51

JavaNIO

2015-09-25 09:14:50

java缓冲技术

2011-12-07 16:12:29

JavaNIO

2011-12-15 10:43:20

JavaNIO

2011-12-15 10:10:33

Javanio
点赞
收藏

51CTO技术栈公众号