JBoss Netty1

はじめに

Javaで非同期I/Oプログラミングを行なうには、バージョン1.4から追加されたNIO(New I/O)を使用する。

NIOをラップした非同期フレームワーク「JBoss Netty」についてご紹介。

Javaでの同期I/O

Javaで同期I/Oを行なう場合、

java.ioパッケージの

  • InputStreamクラス
  • OutputStreamクラス
  • InputStreamReaderクラス
  • BufferedReaderクラス

または、java.netパッケージの

  • ServerSocketクラス
  • Socketクラス

を使う。

Javaでの非同期I/O

Javaで非同期I/Oを行なうには、Java1.4から実装されたjava.nioパッケージの

NIO API

を使う。

同期I/OとClock問題

同期I/Oを使ったサーバプログラム

public class SynchronousServer {
	public static void main(String[] args) throws Exception {
		// スレッドプールを作成する
		ExecutorService threadPool = Executors.newCachedThreadPool();
		// サーバソケットを作成し、8080番ポートにバインドする
		ServerSocket server = new ServerSocket(8080);
		while (true) {
			// クライアントの接続を受け付ける
			final Socket client = server.accept();
			// スレッドプールにクライアントの入出力処理を渡す
			threadPool.submit(new Runnable() {
				public void run() {
					// メソッド本体
					doSomeInputAndOutput(client);
				}
			});
		}
	}
}

シングルスレッドのままだと1度に1つのクライアントしか処理できないため、スレッドプールを使い、入出力処理をワーカスレッドに任せる。

スレッド数が1万を超えるとメモリ消費やコンテキストスイッチにパフォーマンス低下が著しく、サーバが不安定に。

同期I/Oのマルチスレッド方式がネックとなり、1台のサーバで大量の同時接続数を受け付けることが難しくなる。・・・C10K問題

非同期I/Oとイベント駆動モデル

NIOによる非同期型サーバプログラムの例

public class AsynchronousServer {
	public static void main(String[] args) throws Exeption {
		// サーバチャンネルを作成する
		ServerSocketChannel server = ServerSocketChannel.open();
		// ソケットを8080番ポートにバインドする
		server.socket().bind(new InetSocketAddress(8080));
		// チャネルをノンブロキングモードにする
		server.configureBlocking(false);
		// セレクタを作成する
		Selector selector = Selector.open();
		// セレクタを接続受け付け用に登録する
		server.register(selector, SelectionKey.OP_ACCEPT);

		while (true) {
			// I/O処理可能なチャネルを選択する
			selector.select();
			// I/O処理可能なチャネルのキー一覧を取得する
			Iterator keys = selectedKeys.iterator();
			while (keys.hasNext()) {
				SelectionKey key = keys.next();
				// 接続可能なキーの場合
				if (key.isAcceptable()) {
					// クライアントを受け付ける
					SocketChannel client = server.accept();
					if (client != null) {
						// チャネルをノンブロッキングモードにする
						client.configureClocking(false);
						// セレクタをクライアントからの読み込み用に登録する
						client.register(selector, SelectionKey.OP_READ);
					}
				}
				// 読み込み可能なキーの場合
				if (key.isReadable()) {
					// クライアントのチャネルを取得する
					SocketChannel client = (SocketChannel) key.channel();
					// クライアントの入出力処理を行なう
					doSomeAsyncInputAndOutput(client);
				}
				// キーを処理済みとして削除する
				keys.remove();
			}
		}
	}
}

非同期I/Oのソケット通信速度は同期I/Oに劣る。

This entry was posted in Java. Bookmark the permalink.

Comments are closed.