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

被折叠的 条评论
为什么被折叠?



