Selector select方法阻塞register的解决方法

本文探讨了在Java NIO编程中,当Selector的select方法导致register操作阻塞的问题及其解决方案。通过监听端口,当连接到达时创建SocketChannel,避免阻塞现象,确保并发性能。

1. 监听端口, 当连接到来的时候创建socketChannel

public class MultiServer {

	public static void main(String[] args) throws IOException {
		ServerSocketChannel ss = ServerSocketChannel.open().bind(
				new InetSocketAddress(8484));
		final Selector selector = Selector.open();
		wuTiRaw(selector);
		while (true) {
			SocketChannel channel = ss.accept();
			channel.configureBlocking(false);
			channel.register(selector, SelectionKey.OP_READ);
		}
	}

	private static void wuTiRaw(final Selector selector) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					try {
						selector.select();
						Set<SelectionKey> keys = selector
								.selectedKeys();
						Iterator<SelectionKey> it = keys.iterator();
						while (it.hasNext()) {
							SelectionKey next = it.next();
							if (next.isReadable()) {
								ByteBuffer bb = ByteBuffer.allocate(10);
								SocketChannel channel = (SocketChannel) next
										.channel();
								channel.read(bb);
								System.out.println(bb.toString());

							}
							it.remove();
						}
					} catch (IOException e1) {
						e1.printStackTrace();
					}

				}

			}
		});
		t.start();
	}

由于select方法与register 方法都需要获取相同的监视器,故上面的方法会一直阻塞在register方法上

解决如下: 

public class MultiServer {

	public static void main(String[] args) throws IOException {
		ServerSocketChannel ss = ServerSocketChannel.open().bind(
				new InetSocketAddress(8484));
		final Selector selector = Selector.open();
		SelectorHelper sh = new SelectorHelper(selector);
		wuTi(sh);
		while (true) {
			SocketChannel channel = ss.accept();
			channel.configureBlocking(false);
			sh.reg(channel, SelectionKey.OP_READ);
		}
	}
	
	private static void wuTi(final SelectorHelper selector) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					try {
						selector.select();
						Set<SelectionKey> keys = selector.getSelector()
								.selectedKeys();
						Iterator<SelectionKey> it = keys.iterator();
						while (it.hasNext()) {
							SelectionKey next = it.next();
							if (next.isReadable()) {
								ByteBuffer bb = ByteBuffer.allocate(10);
								SocketChannel channel = (SocketChannel) next
										.channel();
								channel.read(bb);
								System.out.println(bb.toString());

							}
							it.remove();
						}
					} catch (IOException e1) {
						e1.printStackTrace();
					}

				}

			}
		});
		t.start();
	}

	public static class SelectorHelper {
		private volatile boolean mark = false;
		private final Selector selector;

		public SelectorHelper(Selector selector) {
			this.selector = selector;
		}

		public Selector getSelector() {
			return selector;
		}
		
		/**
		 * 必须是同步的, 保证多个线程调用reg的时候不会出现问题
		 * @param channel
		 * @param op
		 * @return
		 * @throws ClosedChannelException
		 */
		public synchronized SelectionKey reg(SelectableChannel channel, int op)
				throws ClosedChannelException {
			mark = true;
			selector.wakeup();
			SelectionKey register = channel.register(selector, op);
			mark = false;
			return register;
		}

		public int select() throws IOException {
			for (;;) {
				if (mark == true)
					continue;
				int select = selector.select();
				if (select >= 1)
					return select;
			}
		}
	}
}

betty way:

public class MultiServer2 {
	public static void main(String[] args) throws IOException {
		ServerSocketChannel serverChannel = ServerSocketChannel.open()
				.bind(new InetSocketAddress(8484));
		Selector selector = Selector.open();
		serverChannel.configureBlocking(false);
		serverChannel.register(selector, SelectionKey.OP_ACCEPT);
		while(true) {
			if(selector.select() == 0 ) continue;
			
			Set<SelectionKey> selectedKeys = selector.selectedKeys();
			Iterator<SelectionKey> it = selectedKeys.iterator();
			while(it.hasNext()) {
				SelectionKey next = it.next();
				it.remove();
				handleReady(next, selector);
			}
		}
	}

	private static void handleReady(SelectionKey next, Selector selector) throws IOException {
		if(next.isAcceptable()) {
			ServerSocketChannel channel = (ServerSocketChannel)next.channel();
			SocketChannel accept = channel.accept();
			accept.configureBlocking(false);
			accept.register(selector, SelectionKey.OP_READ);
		}
		if(next.isReadable()) {
			ByteBuffer bb = ByteBuffer.allocate(10);
			SocketChannel channel =(SocketChannel) next.channel();
			channel.read(bb);
			System.out.println(bb);
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值