io
io主要包括2个操作
等待可读(写) 读(写)
其中读(写)的耗时特别短,性能损耗主要在等待就绪上
等待可读的原因
-
用户缓冲区的旧内容还未拷贝到系统空间
-
系统空间的旧内容还未拷贝到硬件
-
硬件不可用
bio
一个连接(socket)一个线程
连接不可读或者写 线程阻塞
切换到其他线程,处理其他的可读写的连接
问题
大量的连接需要大量的线程
线程切换浪费资源
优点
使用简单
nio
https://tech.meituan.com/2016/11/04/nio.html
一个线程处理多个连接
1个连接不可用 切换另一个可读写的连接
优点
不需要在大量线程之间进行切换
缺点
使用较难
java NIO
SelectionKey
public abstract class SelectionKey {
final SelChImpl channel;
public final SelectorImpl selector;
private int index;
private volatile int interestOps;
private int readyOps;
}
Selector
public abstract class Selector implements Closeable {
//生成一个Selector
public static Selector open() throws IOException {
return SelectorProvider.provider().openSelector();
}
//返回所有可操作事件的总数
public abstract int select(long timeout)
throws IOException;
//
public abstract Selector wakeup();
}
SelectorImpl
public abstract class SelectorImpl extends AbstractSelector {
protected Set<SelectionKey> selectedKeys = new HashSet();
protected HashSet<SelectionKey> keys = new HashSet();
private Set<SelectionKey> publicKeys;
private Set<SelectionKey> publicSelectedKeys;
}
final class WindowsSelectorImpl extends SelectorImpl {
//实际的select的实现
//返回所有可操作事件的总数
protected int doSelect(long var1) throws IOException {
if (this.channelArray == null) {
throw new ClosedSelectorException();
} else {
this.timeout = var1;
this.processDeregisterQueue();
if (this.interruptTriggered) {
this.resetWakeupSocket();
return 0;
} else {
this.adjustThreadsCount();
this.finishLock.reset();
this.startLock.startThreads();
try {
this.begin();
try {
//native方法 操作系统级实现
//线程阻塞 直到被内核激活
//当某个socket对应的内存区可读写的时候,会标记socket,并且激活这个线程
//激活后会遍历所有的socket 找到可读写的socket进行操作
this.subSelector.poll();
} catch (IOException var7) {
this.finishLock.setException(var7);
}
if (this.threads.size() > 0) {
this.finishLock.waitForHelperThreads();
}
} finally {
this.end();
}
this.finishLock.checkForException();
this.processDeregisterQueue();
//返回所有有读 写等事件的总数
int var3 = this.updateSelectedKeys();
this.resetWakeupSocket();
return var3;
}
}
}
//唤醒selector
public Selector wakeup() {
synchronized(this.interruptLock) {
if (!this.interruptTriggered) {
this.setWakeupSocket();
this.interruptTriggered = true;
}
return this;
}
}
//注册一个socket 事件
protected void implRegister(SelectionKeyImpl var1) {
synchronized(this.closeLock) {
if (this.pollWrapper == null) {
throw new ClosedSelectorException();
} else {
this.growIfNeeded();
this.channelArray[this.totalChannels] = var1;
var1.setIndex(this.totalChannels);
this.fdMap.put(var1);
this.keys.add(var1);
this.pollWrapper.addEntry(this.totalChannels, var1);
++this.totalChannels;
}
}
}
}