NIO中的Channel主要分爲兩大類:一類是FileChannel,另外一類是SocketChannel。NIO提供的核心非阻塞特性主要針對SocketChannel類,所有socket通道類(DatagramChannel、SocketChannel和ServerSocketChannel)都是由位於java.nio.channels.spi包中的AbstractSelectableChannel引伸而來。這意味着咱們能夠用一個Selector對象來執行socket通道的有條件的選擇(readiness selection)。java
SelectableChannel抽象類提供的方法:socket
請注意DatagramChannel和SocketChannel實現定義讀和寫功能的接口而ServerSocketChannel不實現。ServerSocketChannel負責監聽傳入的鏈接和建立新的SocketChannel對象,它自己從不傳輸數據。所有socket通道類(DatagramChannel、SocketChannel和ServerSocketChannel)在被實例化時都會建立一個對等socket對象。這些是咱們所熟悉的來自java.net的類(Socket、ServerSocket和DatagramSocket),它們已經被更新以識別通道。對等socket能夠經過調用socket( )方法從一個通道上獲取。此外,這三個java.net類如今都有getChannel( )方法。spa
雖然每一個socketChannnel(在java.nio.channels包中)都有一個關聯的java.net socket對象,卻並不是全部的socket都有一個關聯的通道。若是您用傳統方式(直接實例化)建立了一個Socket對象,它就不會有關聯的SocketChannel而且它的getChannel( )方法將老是返回null。.net
示例代碼:線程
@Test public void socketTest() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(8080); } catch (IOException e) { e.printStackTrace(); } ServerSocketChannel channel = serverSocket.getChannel(); assert (channel == null); }
SocketChannel委派協議操做給對等socket對象。若是在通道類中存在彷佛重複的socket方法,那麼將有某個新的或者不一樣的行爲同通道類上的這個方法相關聯。code
默認爲阻塞模式,示例以下:server
@Test public void socketChannelTest() throws Exception { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(8080)); assert (ssc.isBlocking()); ssc.configureBlocking(false); assert (!ssc.isBlocking()); SocketChannel sc = SocketChannel.open(); sc.connect(new InetSocketAddress("localhost", 8080)); }
configureBlocking()是阻塞操做
阻塞非阻塞開關鎖:對象
咱們也會須要防止socket通道的阻塞模式被更改。API中有一個blockingLock( )方法,該方法會返回一個非透明的對象引用。返回的對象是通道實現修改阻塞模式時內部使用的。只有擁有此對象的鎖的線程才能更改通道的阻塞模式(對象的鎖是用同步的Java密碼獲取的)。對於確保在執行代碼的關鍵部分時socket通道的阻塞模式不會改變以及在不影響其餘線程的前提下暫時改變阻塞模式來講,這個方法都是很是方便的。blog
代碼示例:接口
/** * configureBlocking Test * @throws Exception */ @Test public void socketChannelConfigureBlockingTest() throws Exception { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(8080)); assert (ssc.isBlocking()); ssc.configureBlocking(false); assert (!ssc.isBlocking()); Object lock = ssc.blockingLock(); Thread thread = new Thread(()->{ Date date = new Date(); try { TimeUnit.SECONDS.sleep(3); date = new Date(); //阻塞操做 ssc.configureBlocking(true); } catch (Exception e) { e.printStackTrace(); assert (false); } assert (ssc.isBlocking()); assert (new Date().getTime()-date.getTime()>=6000); }); thread.start(); synchronized (lock){ TimeUnit.SECONDS.sleep(10); } thread.join(); }