JAVA BIO、NIO、原子炉モデルの概要

伝統的な同期ブロッキングI / O(BIO)

前NIOに使用するサーバーを書くのI / O(I / Oブロッキング)同期ブロックです。serverSocket.accept()、及びIOを読み取るため、ここで()、接続の数が急増した場合に、サーバコードは役に立たないだろうサーバスレッドプール顧客サービス側のコードの典型的な例であり、書き込み(スレッドプールによって、頻繁なスレッドのオーバーヘッドを作成回避するが)方法は、同期ブロックであるが、システムがスレッドに依存しすぎている、スレッドの生成および破壊は特にで、オーバーヘッドスイッチング非常に時間がかかる。さらに優れたスレッドでありますシステム圧力が高い並行性の場合には考えられないであろう。

BIO顧客端末サーバスレッドプールのサンプルコード

/**
 * BIO服务器
 * @author monkjavaer
 * @date 2019/7/17 13:55
 */
public class BioServer {
    public static final int PORT = 8888;
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(PORT);
            Socket socket = null;
            ThreadFactory namedThreadFactory = new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r);
                    t.setName("demo-pool-%d");
                    return t;
                }
            };
            //通过线程池,避免频繁创建线程开销
            ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

            //主线程死循环等待新连接到来
            while(!Thread.currentThread().isInterrupted()){
                socket = serverSocket.accept();
                singleThreadPool.execute(new BioServerHandler(socket));
            }
        } catch (IOException e) {
            //TODO异常处理
        } finally {
         //TODO关闭资源
        }
    }
}
/**
 * BIO服务器事件处理方法
 * @author monkjavaer
 * @date 2019/7/17 14:00
 */
public class BioServerHandler implements Runnable {
    private Socket socket;
    public BioServerHandler(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            byte[] input = new byte[1024];
            //服务器接收的数据
            socket.getInputStream().read(input);
            byte[] output = "服务器返回数据".getBytes();
            socket.getOutputStream().write(output);
       } catch (IOException e) {
            //TODO异常处理
        } finally {
         //TODO关闭资源
        }
    }
}
/**
 * 服务端
 * @author monkjavaer
 * @date 2019/7/17 15:06
 */
public class BioClient {
    public static final int PORT = 8888;
    public static final String IP = "127.0.0.1";
    public static void main(String[] args) {
        Socket socket = null;
        PrintWriter printWriter = null;
        try {
            socket = new Socket(IP,PORT);
            socket.setSoTimeout(5000);
            printWriter = new PrintWriter(socket.getOutputStream());
            printWriter.println("客户端发送数据");
            printWriter.flush();
        } catch (IOException e) {
            //TODO异常处理
        } finally {
         //TODO关闭资源
        }
    }
}

NIO(非ブロッキングI / O)

NIOは、ノンブロッキングI / O(非ブロックI / O)であります

NIOの重要なコンポーネントの評価

  • 緩衝液(バッファ):オブジェクトバッファは、データコンテナの固定数です。その役割は、メモリ、またはデータを格納および検索した後に使用することができるステージングエリアです。ByteBufferの、IntBuffer、CharBufferの、LongBuffer、のDoubleBuffer、FloatBuffer、ShortBufferは、その実装クラスです。
  • チャンネル(チャンネル):チャンネルバイトバッファと反対側のエンティティの通路(典型的には、ファイルやソケット)効率との間でデータを転送するため。チャネルは、全二重です。
  • セレクタ(セレクタ):セレクタマルチプレクサがNIOです。セレクタは、チャネル、チャネルの、レディ状態チャンネル(チャンネルチャネルはイベントを読み書き発生)を見つけるに登録された世論調査していきます。セレクタ機構は、基礎となるオペレーティングシステム、異なるモデル、異なるバージョンの違いに基づいています。Linux上でのepollに依存し、最大ハンドルに制限はありません、これを行うセレクタポーリング・スレッドが大量のクライアント接続にアクセスすることができます。

NIOサーバーのサンプルコード

NIOサーバーコードのステップは非常にはるかに複雑達成するために、ように成熟したフレームワークNIOネッティーとを使用することをお勧めします。

public class NioServer implements Runnable {
    private static Logger LOGGER = LoggerFactory.getLogger(NioServer.class);
    @Override
    public void run() {
        try {
            //1、打开ServerSocketChannel,监听客户端的链接
            ServerSocketChannel serverSocket = ServerSocketChannel.open();
            //2、绑定监听端口,设置backlog(默认50):请求传入连接队列的最大长度
            serverSocket.socket().bind(new InetSocketAddress(9011), 1024);
            //3、false,设置为非阻塞模式
            serverSocket.configureBlocking(false);
            //4、创建Selector,Selector是NIO的多路复用器,Selector会不断轮询注册在它上面的通道Channel,
            //找出就绪状态的Channel(Channel通道发生读、写事件)。
            Selector selector = Selector.open();
            //5、注册通道Channel到多路复用器Selector,并说明关注点SelectionKey.OP_ACCEPT,监听ACCEPT事件
            serverSocket.register(selector, SelectionKey.OP_ACCEPT);
            LOGGER.info("Listening on port {}" , 9011);

            //6、Selector轮询就绪的Channel
            while (true) {
                // 阻塞等待就绪的 Channel,这是关键点之一
                //selector1秒被唤醒
                int n = selector.select(1000);
                if (n == 0) {
                    continue;
                }
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> iter = selectedKeys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    if (key.isValid()) {

                        if (key.isAcceptable()) {
                            //SelectionKey可以获取就绪状态的Channel
                            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                            //7、多路复用器Selector监听到有新的客户端连接,完成TCP三次握手建立连接。
                            SocketChannel clientSocketChannel = serverSocketChannel.accept();
                            //8、设置客户端SocketChannel为非阻塞模式
                            clientSocketChannel.configureBlocking(false);
                            //9、注册加入新的通道OP_READ
                            clientSocketChannel.register(selector, SelectionKey.OP_READ);
                        }

                        //读取客户端数据
                        //if(key.isReadable())等价于if((key.readyOps( ) & SelectionKey.OP_READ) != 0)
                        if (key.isReadable()) {
                            SocketChannel socketChannel = (SocketChannel) key.channel();
                            //创建buffer
                            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                            int readPosition = socketChannel.read(readBuffer);
                            if (readPosition > 0) {
                                //flip()方法,Buffer从写模式切换到读模式,将limit设置为position,position设为0。
                                readBuffer.flip();
                                byte[] bytes = new byte[readBuffer.remaining()];
                                //从可读buffer中读取数据
                                readBuffer.get(bytes);
                                LOGGER.info("接收客户端发送消息:{}" , new String(bytes, StandardCharsets.UTF_8));

                                byte[] sendBytes = "server 收到".getBytes();
                                ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
                                writeBuffer.flip();
                                //put 向buffer添加元素
                                writeBuffer.put(sendBytes);
                                socketChannel.write(writeBuffer);
                            }

                            if (readPosition < 0) {
                                // Close channel on EOF, invalidates the key
                                key.cancel();
                                socketChannel.close();
                            }
                        }
                    }
                    iter.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new NioServer()).start();
    }
}
public class NioClient {
    private static Logger LOGGER = LoggerFactory.getLogger(NioClient.class);
    private static int PORT = 9011;
    private static String[] messages = {"这是服务器"};

    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), PORT));
            for (String msg : messages) {
                ByteBuffer myBuffer = ByteBuffer.allocate(1024);
                myBuffer.put(msg.getBytes());
                myBuffer.flip();
                socketChannel.write(myBuffer);
            }
            LOGGER.info("Closing Client connection...");
            socketChannel.close();
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
        }
    }

}

原子炉モード

第一反応器のパターンは、イベント駆動型の、一つ以上の入力ソースと同時である、サービス・ハンドラ、複数のリクエストハンドラがあり、サービスハンドラ(イベント)を要求する多重入力同期を配布するために、対応しますハンドラーを要求。これは、並行サービス要求のためのプロセスであり、要求は、1つ以上のサービス・モデルに設計されたイベントハンドラに提出されます。

原子炉モード・モジュール

http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html

Javaのテキストと翻訳でスケーラブルなIO

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf
https://www.cnblogs.com/luxiaoxun/archive/2015/03/11/4331110.html

逆多重化のためのオブジェクトの行動パターンを反応器と同期イベントのハンドルを派遣

http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf

おすすめ

転載: www.cnblogs.com/monkjavaer/p/11209141.html