架构图
1.单线程
处理多个通道 就不需要创建那么多线程 不需要线程来回切换
2.选择器
用来选择一个通道
3.通道 1)一个服务器端通道(最终对应操作系统的服务器端套接字) 2)每个客户端连接都有一个连接通道(最终对应操作系统的客户端套接字) file:///var/folders/m9/yshd99dx1g38gtyxvv3k201r0000gn/T/WizNote/6a23daf1-067c-4096-86d6-f5fe1fd20958/index_files/f82c56ef-6b45-4a04-bea0-e79f0dc40a13.jpg
类继承图
1.接口
2.抽象类
3.实现类
核心类
1.选择器Selector
2.选择器提供者SelectorProvider
源码分析
创建选择器/选择器提供者 对象
public abstract class Selector implements Closeable {
/**
* Initializes a new instance of this class.
*/
protected Selector() { }
/**
* Opens a selector.
*
* <p> The new selector is created by invoking the {@link
* java.nio.channels.spi.SelectorProvider#openSelector openSelector} method
* of the system-wide default {@link
* java.nio.channels.spi.SelectorProvider} object. </p>
*
* @return A new selector
*
* @throws IOException
* If an I/O error occurs
*/
public static Selector open() throws IOException {
return SelectorProvider.provider().openSelector(); //KQueueSelectorProvider
}
public class KQueueSelectorProvider
extends SelectorProviderImpl
{
public AbstractSelector openSelector() throws IOException {
return new KQueueSelectorImpl(this);
}
}
public abstract class AbstractSelector
extends Selector
{
private AtomicBoolean selectorOpen = new AtomicBoolean(true);
// The provider that created this selector
private final SelectorProvider provider; //Selector和SelectorProvider:1.Selector包含了提供者SelectorProvider 2.提供者创建Selector
/**
* Initializes a new instance of this class.
*
* @param provider
* The provider that created this selector
*/
protected AbstractSelector(SelectorProvider provider) {
this.provider = provider;
}
注册通道到选择器
通道和选择器的关系?
通道实现了选择器 但是底层注册还是调用选择器.注册:通道.注册——》选择器.注册
public final SelectionKey register(Selector sel //选择器实现类, int ops //监听事件,
Object att)
throws ClosedChannelException
{
synchronized (regLock) {
if (!isOpen())
throw new ClosedChannelException();
if ((ops & ~validOps()) != 0)
throw new IllegalArgumentException();
if (blocking)
throw new IllegalBlockingModeException();
SelectionKey k = findKey(sel);
if (k != null) {
k.interestOps(ops);
k.attach(att);
}
if (k == null) {
// New registration
synchronized (keyLock) {
if (!isOpen())
throw new ClosedChannelException();
k = ((AbstractSelector)sel).register(this, ops, att); //注册
addKey(k);
}
}
return k;
}
}
选择通道
public abstract class SelectorImpl
extends AbstractSelector
{
private int lockAndDoSelect(long timeout) throws IOException {
synchronized (this) {
if (!isOpen())
throw new ClosedSelectorException();
synchronized (publicKeys) {
synchronized (publicSelectedKeys) {
return doSelect(timeout); //选择
}
}
}
}
class KQueueSelectorImpl
extends SelectorImpl
{
protected int doSelect(long timeout)
throws IOException
{
int entries = 0;
if (closed)
throw new ClosedSelectorException();
processDeregisterQueue(); //
try {
begin(); //
entries = kqueueWrapper.poll(timeout); //阻塞:主要是里面调用kevent0会阻塞
} finally {
end();
}
processDeregisterQueue();
return updateSelectedKeys(entries); //
}
class KQueueArrayWrapper {
int poll(long timeout) {
updateRegistrations(); //
int updated = kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout); //native方法 //阻塞
return updated;
}
void updateRegistrations() {
synchronized (updateList) {
Update u = null;
while ((u = updateList.poll()) != null) {
SelChImpl ch = u.channel;
if (!ch.isOpen())
continue;
register0(kq, ch.getFDVal(), u.events & POLLIN, u.events & POLLOUT); //native方法
}
}
}
/**
* Update the keys whose fd's have been selected by kqueue.
* Add the ready keys to the selected key set.
* If the interrupt fd has been selected, drain it and clear the interrupt.
*/
private int updateSelectedKeys(int entries)
throws IOException
{
int numKeysUpdated = 0;
boolean interrupted = false;
// A file descriptor may be registered with kqueue with more than one
// filter and so there may be more than one event for a fd. The update
// count in the MapEntry tracks when the fd was last updated and this
// ensures that the ready ops are updated rather than replaced by a
// second or subsequent event.
updateCount++;
for (int i = 0; i < entries; i++) {
int nextFD = kqueueWrapper.getDescriptor(i);
if (nextFD == fd0) {
interrupted = true;
} else {
MapEntry me = fdMap.get(Integer.valueOf(nextFD));
// entry is null in the case of an interrupt
if (me != null) {
int rOps = kqueueWrapper.getReventOps(i);
SelectionKeyImpl ski = me.ski;
if (selectedKeys.contains(ski)) {
// first time this file descriptor has been encountered on this
// update?
if (me.updateCount != updateCount) {
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
numKeysUpdated++;
me.updateCount = updateCount;
}
} else {
// ready ops have already been set on this update
ski.channel.translateAndUpdateReadyOps(rOps, ski);
}
} else {
ski.channel.translateAndSetReadyOps(rOps, ski);
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
selectedKeys.add(ski);
numKeysUpdated++;
me.updateCount = updateCount;
}
}
}
}
}
if (interrupted) {
// Clear the wakeup pipe
synchronized (interruptLock) {
IOUtil.drain(fd0);
interruptTriggered = false;
}
}
return numKeysUpdated;
}