基於JDK8
Selector在NIO部分會使用到,尤其是Netty中
創建Selector
如下List-1,使用靜態方法來創建,間接通過SelectorProvider來實現的
List-1
public abstract class Selector implements Closeable {
/**
* 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();
}
如下List-2中,select()會一直阻塞,直到有channel返回或者Selector.wakeup()被調用;select(timeout)會阻塞timeout段時間;selectNow()會直接返回,不管是否有channel返回
List-2
/**
* Selects a set of keys whose corresponding channels are ready for I/O
* operations.
*
* <p> This method performs a non-blocking <a href="#selop">selection
* operation</a>. If no channels have become selectable since the previous
* selection operation then this method immediately returns zero.
*
* <p> Invoking this method clears the effect of any previous invocations
* of the {@link #wakeup wakeup} method. </p>
*
* @return The number of keys, possibly zero, whose ready-operation sets
* were updated by the selection operation
*
* @throws IOException
* If an I/O error occurs
*
* @throws ClosedSelectorException
* If this selector is closed
*/
public abstract int selectNow() throws IOException;
/**
* Selects a set of keys whose corresponding channels are ready for I/O
* operations.
*
* <p> This method performs a blocking <a href="#selop">selection
* operation</a>. It returns only after at least one channel is selected,
* this selector's {@link #wakeup wakeup} method is invoked, the current
* thread is interrupted, or the given timeout period expires, whichever
* comes first.
*
* <p> This method does not offer real-time guarantees: It schedules the
* timeout as if by invoking the {@link Object#wait(long)} method. </p>
*
* @param timeout If positive, block for up to <tt>timeout</tt>
* milliseconds, more or less, while waiting for a
* channel to become ready; if zero, block indefinitely;
* must not be negative
*
* @return The number of keys, possibly zero,
* whose ready-operation sets were updated
*
* @throws IOException
* If an I/O error occurs
*
* @throws ClosedSelectorException
* If this selector is closed
*
* @throws IllegalArgumentException
* If the value of the timeout argument is negative
*/
public abstract int select(long timeout)
throws IOException;
/**
* Selects a set of keys whose corresponding channels are ready for I/O
* operations.
*
* <p> This method performs a blocking <a href="#selop">selection
* operation</a>. It returns only after at least one channel is selected,
* this selector's {@link #wakeup wakeup} method is invoked, or the current
* thread is interrupted, whichever comes first. </p>
*
* @return The number of keys, possibly zero,
* whose ready-operation sets were updated
*
* @throws IOException
* If an I/O error occurs
*
* @throws ClosedSelectorException
* If this selector is closed
*/
public abstract int select() throws IOException;
如下List-3,provider()方法中
- loadProviderFromProperty,從System.getProperty()中獲取類名稱,之後反射獲取實例
- loadProviderAsService,同JDK的SPI方式,SPI返回的是一個集合,但是這裏只會取集合第一個元素
- DefaultSelectorProvider,如果上面倆者都沒有,則使用DefaultSelectorProvider進行創建,如List-4所示,所以真正的SelectorProvider實現類是KQueueSelectorProvider
由此可見,JDK中的設計,還是很留有餘地給使用者進行個性化實現的
List-3
public abstract class SelectorProvider {
private static final Object lock = new Object();
private static SelectorProvider provider = null;
private static boolean loadProviderFromProperty() {
String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");
if (cn == null)
return false;
try {
Class<?> c = Class.forName(cn, true,
ClassLoader.getSystemClassLoader());
provider = (SelectorProvider)c.newInstance();
return true;
} catch (ClassNotFoundException x) {
throw new ServiceConfigurationError(null, x);
} catch (IllegalAccessException x) {
throw new ServiceConfigurationError(null, x);
} catch (InstantiationException x) {
throw new ServiceConfigurationError(null, x);
} catch (SecurityException x) {
throw new ServiceConfigurationError(null, x);
}
}
private static boolean loadProviderAsService() {
ServiceLoader<SelectorProvider> sl =
ServiceLoader.load(SelectorProvider.class,
ClassLoader.getSystemClassLoader());
Iterator<SelectorProvider> i = sl.iterator();
for (;;) {
try {
if (!i.hasNext())
return false;
provider = i.next();
return true;
} catch (ServiceConfigurationError sce) {
if (sce.getCause() instanceof SecurityException) {
// Ignore the security exception, try the next provider
continue;
}
throw sce;
}
}
}
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
if (loadProviderFromProperty())
return provider;
if (loadProviderAsService())
return provider;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
List-4
public class DefaultSelectorProvider {
private DefaultSelectorProvider() {
}
public static SelectorProvider create() {
return new KQueueSelectorProvider();
}
}