看thrift源码发现selector.wakeup()方法,通常在selector.select()后线程会阻塞。使用wakeup()方法,线程会立即返回。源码分析应该是用的线程中断实现的。下面是个小demo
public class TestSelector { private static Selector selector; public static void main(String[] args) throws IOException, InterruptedException { startSelectorThread(); Thread.sleep(2000); selector.wakeup(); } private static void startSelectorThread(){ Runnable selectorTask = () -> { try{ String host = "127.0.0.1"; int port = 8888; ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); SocketAddress socketAddress = new InetSocketAddress(host, port); serverSocketChannel.bind(socketAddress); selector = Selector.open(); while(true){ serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("selector start select ....."); Set<SelectionKey> selectionKeySet = selector.selectedKeys(); for(Iterator<SelectionKey> iterator = selectionKeySet.iterator(); iterator.hasNext(); ){ SelectionKey selectionKey = iterator.next(); System.out.println(selectionKey.toString()); selectionKeySet.remove(selectionKey); ServerSocketChannel serverSocketChannel1 = (ServerSocketChannel) selectionKey.channel(); SocketChannel clientChannel = serverSocketChannel1.accept(); clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); iterator.remove(); } System.out.println("selector end select ...."); } }catch (Exception e){ e.printStackTrace(); } }; //task Thread thread = new Thread(selectorTask); thread.start(); } }
我们看下wakeup()注释
/** * Causes the first selection operation that has not yet returned to return * immediately. * * <p> If another thread is currently blocked in an invocation of the * {@link #select()} or {@link #select(long)} methods then that invocation * will return immediately. If no selection operation is currently in * progress then the next invocation of one of these methods will return * immediately unless the {@link #selectNow()} method is invoked in the * meantime. In any case the value returned by that invocation may be * non-zero. Subsequent invocations of the {@link #select()} or {@link * #select(long)} methods will block as usual unless this method is invoked * again in the meantime. * * <p> Invoking this method more than once between two successive selection * operations has the same effect as invoking it just once. </p> * * @return This selector */ public abstract Selector wakeup();
可以看出,这个方法会让阻塞的线程立即返回。跟进poll实现的selector的wakeup()方法
public Selector wakeup() { Object var1 = this.interruptLock; synchronized(this.interruptLock) { if (!this.interruptTriggered) { this.pollWrapper.interrupt(); this.interruptTriggered = true; } return this; } }
上面可以看出使用的是interrupt()给线程发个中断信号实现的