一、前言

  前面学习了缓冲区的相关知识点,接下来学习通道。

二、通道

  2.1 层次结构图

  对于通道的类层次结构如下图所示。

  

  其中,Channel是所有类的父类,其定义了通道的基本操作。从 Channel 接口引申出的其他接口都是面向字节的子接口,包括 WritableByteChannel和ReadableByteChannel。这也意味着通道只能在字节缓冲区上操作

  2.2 通道基础

  Channel接口类只定义了两个方法(isOpen和close),分别表示通道是否打开和关闭通道,具体细节需要子类实现。   

  IO操作可分为File IO和Stream IO,对应通道也有它们是文件( file)通道和套接字( socket)通道 。通道可以有多种方式创建。Socket 通道有可以直接创建新 socket 通道的工厂方法。但File通道不能直接创建,只能通过在一个打开的RandomAccessFile、FileInputStream或FileOutputStream的对象上调用getChannel( )方法来获取。

  通道将数据传输给 ByteBuffer 对象或者从 ByteBuffer 对象获取数据进行传输,通道可以是单向( unidirectional)或者双向的( bidirectional)。一个 channel 类可能实现定义read( )方法的 ReadableByteChannel 接口,而另一个 channel 类也许实现 WritableByteChannel 接口以提供 write( )方法。实现这两种接口其中之一的类都是单向的,只能在一个方向上传输数据。如果一个类同时实现这两个接口,那么它是双向的,可以双向传输数据。如ByteChannel 接口,该接口继承 ReadableByteChannel 和WritableByteChannel 两个接口,可双向传输数据。

  值得注意的是,从 FileInputStream 对象的getChannel( )方法获取的 FileChannel 对象是只读的,不过从接口声明的角度来看却是双向的,因为FileChannel 实现 ByteChannel 接口。在这样一个通道上调用 write( )方法将抛出未经检查的NonWritableChannelException 异常,因为 FileInputStream 对象总是以 read-only 的权限打开文件。

  通道会连接一个特定 I/O 服务且通道实例( channel instance)的性能受它所连接的 I/O 服务的特征限制。如一个连接到只读文件的 Channel 实例不能进行写操作,即使该实例所属的类可能有 write( )方法。

  通道可以以阻塞( blocking)或非阻塞( nonblocking)模式运行,非阻塞模式的通道永远不会让调用的线程休眠。请求的操作要么立即完成,要么返回一个结果表明未进行任何操作。只有面向流的( stream-oriented)的通道,如 sockets 和 pipes 才能使用非阻塞模式。

  通道不能被重复使用,一个打开的通道即代表与一个特定 I/O 服务的特定连接并封装该连接的状态。当通道关闭时,连接会丢失,通道将不再连接任何东西

  2.3 Scatter/Gather

  Scatter/Gather是指在多个缓冲区上实现一个简单的 I/O 操作。

  对于write操作而言,数据是从几个缓冲区按顺序抽取(称为 gather)并沿着通道发送的,该 gather 过程的效果好比将全部缓冲区的内容连结起来,并在发送数据前存放到一个大的缓冲区中。

  对于read操作而言,从通道读取的数据会按顺序被散布(称为 scatter)到多个缓冲区,将每个缓冲区填满直至通道中的数据或者缓冲区的最大空间被消耗完。

  如下代码片段,假定 channel 连接到一个有 48 字节数据等待读取的 socket 上

  1. ByteBuffer header = ByteBuffer.allocateDirect (10);
  2. ByteBuffer body = ByteBuffer.allocateDirect (80);
  3. ByteBuffer [] buffers = { header, body };
  4. int bytesRead = channel.read (buffers);

  此时,bytesRead为48,header 缓冲区将包含前 10 个从通道读取的字节而 body 缓冲区则包含接下来的 38 个字节,紧接着,下面代码片段  

  1. body.clear( );
  2. body.put("FOO".getBytes()).flip( ); // "FOO" as bytes
  3. header.clear( );
  4. header.putShort (TYPE_FILE).putLong (body.limit()).flip( );
  5. long bytesWritten = channel.write (buffers);

  则将不同buffer(header、body)中的数据gather起来写入通道,总共发送13个字节(3 + 2 + 8)。

  Scatter和Gather将读取到的数据分开存放到多个存储桶( bucket)或者将不同的数据区块合并成一个整体

  2.4 文件通道

  FileChannel 类可以实现常用的 read, write 以及 scatter/gather 操作,同时它也提供了很多专用于文件的新方法。并且文件通道总是阻塞式的,因此不能被置于非阻塞模式。对于文件 I/O,最强大之处在于异步 I/O( asynchronous I/O),它允许一个进程可以从操作系统请求一个或多个 I/O 操作而不必等待这些操作的完成,发起请求的进程之后会收到它请求的 I/O 操作已完成的通知。

  FileChannel不能直接创建,需要使用getChannel方法获取,并且其是线程安全( thread-safe)的。多个进程可以在同一个实例上并发调用方法而不会引起任何问题,不过并非所有的操作都是多线程的,如影响通道位置或者影响文件大小的操作都是单线程的,如果一个线程在执行会影响通道位置或文件大小时,那么其他尝试进行此类操作的线程必须等待。

  每个 FileChannel 对象与文件描述符是一对一关系,同底层的文件描述符一样,每个 FileChannel 都有一个叫"file position"的概念,这个position值决定文件中哪一处的数据接下来将被读或者写,这与缓冲非常相似。

  FileChannel 位置( position)是从底层的文件描述符获得的,该 position 同时被作为通道引用获取来源的文件对象共享。这也就意味着一个对象对该 position 的更新可以被另一个对象看到,如下代码片段  

  1. RandomAccessFile randomAccessFile = new RandomAccessFile ("filename", "r");
  2. // Set the file position
  3. randomAccessFile.seek (1000);
  4. // Create a channel from the file
  5. FileChannel fileChannel = randomAccessFile.getChannel( );
  6. // This will print "1000"
  7. System.out.println ("file pos: " + fileChannel.position( ));
  8. // Change the position using the RandomAccessFile object
  9. randomAccessFile.seek (500);
  10. // This will print "500"
  11. System.out.println ("file pos: " + fileChannel.position( ));
  12. // Change the position using the FileChannel object
  13. fileChannel.position (200);
  14. // This will print "200"
  15. System.out.println ("file pos: " + randomAccessFile.getFilePointer( ));

  可以看到,随着randomAccessFile设置不同的position,fileChannel的position也会相应的跟着改变。

  类似于缓冲区的 get( ) 和 put( )方法,当字节被 read( )或 write( )方法传输时,文件 position 会自动更新。如果 position 值达到了文件大小的值(文件大小的值可以通过 size( )方法返回), read( )方法会返回一个文件尾条件值( -1)。可是,不同于缓冲区的是,如果实现 write( )方法时 position前进到超过文件大小的值,该文件会扩展以容纳新写入的字节

  同样类似于缓冲区,也有带 position 参数的绝对形式的 read( )和 write( )方法。这种绝对形式的方法在返回值时不会改变当前的文件 position。由于通道的状态无需更新,因此绝对的读和写可能会更加有效率,操作请求可以直接传到本地代码。更妙的是,多个线程可以并发访问同一个文件而不会相互产生干扰。这是因为每次调用都是原子性的( atomic),并不依靠调用之间系统所记住的状态。

  对于FileChannel实现的文件锁定模型而言,锁的对象是文件而不是通道或线程,这意味着文件锁不适用于判优同一台 Java 虚拟机上的多个线程发起的访问。如果一个线程在某个文件上获得了一个独占锁,然后第二个线程利用一个单独打开的通道来请求该文件的独占锁,那么第二个线程的请求会抛出OverlappingFileLockException异常。但如果这两个线程运行在不同的 Java 虚拟机上,那么第二个线程会阻塞,因为锁最终是由操作系统或文件系统来判优的并且几乎总是在进程级而非线程级(同一JVM上的线程)上判优。锁都是与一个文件关联的,而不是与单个的文件句柄或通道关联。如下示例展示了同一JVM上的两个线程使用同一文件锁。  

  1. import java.io.FileOutputStream;
  2. import java.nio.channels.FileChannel;
  3. import java.nio.channels.FileLock;
  4.  
  5. /**
  6. * Created by LEESF on 2017/4/16.
  7. */
  8. public class FileLockDemo {
  9. public static void main(String[] args) throws Exception {
  10. FileOutputStream fileOutputStream = new FileOutputStream("F://test.txt");
  11. FileChannel fileChannel = fileOutputStream.getChannel();
  12.  
  13. Thread thread1 = new Thread(new MyRunnalbe(fileChannel));
  14. Thread thread2 = new Thread(new MyRunnalbe(fileChannel));
  15.  
  16. thread1.start();
  17. thread2.start();
  18. }
  19.  
  20. static class MyRunnalbe implements Runnable {
  21. private FileChannel fileChannel;
  22.  
  23. public MyRunnalbe(FileChannel fileChannel) {
  24. this.fileChannel = fileChannel;
  25. }
  26.  
  27. @Override
  28. public void run() {
  29. try {
  30. FileLock fileLock= fileChannel.lock();
  31. System.out.println(fileLock.isValid());
  32. Thread.sleep(1000);
  33. } catch (Exception ex) {
  34. System.out.println(Thread.currentThread().getName() + " " + ex);
  35. }
  36. }
  37. }
  38. }

  输出结果  

  1. true
  2. Thread-1 java.nio.channels.OverlappingFileLockException

  可以看到,当thread2获取锁后,thread1再获取锁时,发出现异常。

  锁与文件关联,而不是与通道关联。我们使用锁来判优外部进程,而不是判优同一个 Java 虚拟机上的线程

  2.5 内存映射文件

  新的 FileChannel 类提供了一个名为 map( )的方法,该方法可以在一个打开的文件和一个特殊类型的 ByteBuffer 之间建立一个虚拟内存映射,由 map( )方法返回的 MappedByteBuffer 对象的行为类似与基于内存的缓冲区,只不过该对象的数据元素存储在磁盘上的文件中。通过内存映射机制来访问一个文件会比使用常规方法读写高效得多,甚至比使用通道的效率都高。

  当需要映射整个文件时,可使用如下代码片段 

  1. buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());

  与文件锁的范围机制不一样,映射文件的范围不应超过文件的实际大小。如果您请求一个超出文件大小的映射,文件会被增大以匹配映射的大小。

  同常规的文件句柄类似,文件映射可以是可写的或只读的。前两种映射模式MapMode.READ_ONLY 和 MapMode.READ_WRITE 意义是很明显的,它们表示你希望获取的映射只读还是允许修改映射的文件。请求的映射模式将受被调用 map( )方法的 FileChannel 对象的访问权限所限制,如果通道是以只读的权限打开的而您却请求 MapMode.READ_WRITE 模式,那么map( )方法会抛出一个 NonWritableChannelException 异常;如果您在一个没有读权限的通道上请求MapMode.READ_ONLY 映射模式,那么将产生 NonReadableChannelException 异常。不过在以read/write 权限打开的通道上请求一个 MapMode.READ_ONLY 映射却是允许的。而MapMode.PRIVATE 模式表示一个写时拷贝( copy-on-write)的映射,这意味着通过 put( )方法所做的任何修改都会导致产生一个私有的数据拷贝并且该拷贝中的数据只有MappedByteBuffer 实例可以看到。该过程不会对底层文件做任何修改,而且一旦缓冲区被施以垃圾收集动作( garbage collected),那些修改都会丢失。

  FileChannel的transferTo( )和 transferFrom( )方法允许将一个通道交叉连接到另一个通道,而不需要通过一个中间缓冲区来传递数据。

  2.6 Socket通道

  Socket 通道有与文件通道不同的特征, 一个或几个线程就可以管理成百上千的活动 socket 连接了并且只有很少甚至可能没有性能损失。

  DatagramChannel 和 SocketChannel 实现定义读和写功能的接口而 ServerSocketChannel不实现。 ServerSocketChannel 负责监听传入的连接和创建新的 SocketChannel 对象,它本身从不传输数据。socket 通道类( DatagramChannel、SocketChannel和ServerSocketChannel)在被实例化时都会创建一个对等socket对象。

  所有通道可以在非阻塞情况下运行,这依托于SelectableChannel,使用其configureBlocking方法即可配置是否阻塞。

  ServerSocketChannel 是一个基于通道的 socket 监听器,能够在非阻塞模式下运行。

  当需要对一个端口进行监听时,需要获取通道对应的 socket,然后使用socket绑定到指定端口进行监听,常用代码如下 

  1. ServerSocketChannel ssc = ServerSocketChannel.open( );
  2. ServerSocket serverSocket = ssc.socket( );
  3. // Listen on port 1234
  4. serverSocket.bind (new InetSocketAddress (1234));

  在完成绑定后,可以使用ServerSocketChannel或者ServerSocket的accept方法来接受到达通道的连接,当使用ServerSocketChannel的accept时,会返回 SocketChannel 类型的对象,返回的对象能够在非阻塞模式下运行。 而当使用ServerSocket时的accept时,总是阻塞并返回一个 java.net.Socket 对象。因此较优的做法是使用ServerSocketChannel的accept方法,下面是监听1234端口的示例。 

  1. import java.nio.ByteBuffer;
  2. import java.nio.channels.ServerSocketChannel;
  3. import java.nio.channels.SocketChannel;
  4. import java.net.InetSocketAddress;
  5.  
  6. /**
  7. * Created by LEESF on 2017/4/16.
  8. */
  9.  
  10. public class ChannelAccept {
  11. public static final String GREETING = "Hello I must be going.\r\n";
  12.  
  13. public static void main (String [] argv) throws Exception {
  14. int port = 1234; // default
  15. if (argv.length > 0) {
  16. port = Integer.parseInt (argv [0]);
  17. }
  18. ByteBuffer buffer = ByteBuffer.wrap (GREETING.getBytes( ));
  19. ServerSocketChannel ssc = ServerSocketChannel.open( );
  20. ssc.socket( ).bind (new InetSocketAddress (port));
  21. ssc.configureBlocking (false);
  22. while (true) {
  23. System.out.println ("Waiting for connections");
  24. SocketChannel sc = ssc.accept( );
  25. if (sc == null) {
  26. // no connections, snooze a while
  27. Thread.sleep (2000);
  28. } else {
  29. System.out.println ("Incoming connection from: "
  30. + sc.socket().getRemoteSocketAddress( ));
  31. buffer.rewind( );
  32. sc.write (buffer);
  33. sc.close( );
  34. }
  35. }
  36. }
  37. }

   SocketChannel是使用最多的 socket 通道类,Socket 和 SocketChannel 类封装点对点、有序的网络连接,类似于 TCP/IP网络连接,SocketChannel 扮演客户端,会发起和一个监听服务器的连接。每个 SocketChannel 对象创建时都会同一个对等的 java.net.Socket 对象对应。

  下面代码片段会连接指定主机的指定端口。  

  1. SocketChannel socketChannel = SocketChannel.open( );
  2. socketChannel.connect (new InetSocketAddress ("somehost", somePort));

  如果通过Socket的connect方法进行连接,那么线程在连接建立好或超时过期之前都将保持阻塞;而若通过SocketServer的connect方法进行连接,那么会对发起对请求地址的连接并且立即返回值。如果返回值是 true,说明连接立即建立了(这可能是本地环回连接);如果连接不能立即建立, connect( )方法会返回 false 且并发地继续连接建立过程。

  Socket 通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程,不过任何时候都只有一个读操作和一个写操作在进行中。

  如下示例完成了客户端向服务端之间的数据传送,使用ServerSocketChannel充当服务端,SocketChannel充当客户端,客户端向服务端发送数据,服务端接收后响应客户端,然后服务端关闭,客户端接收到响应数据后,关闭,代码如下

  服务端  

  1. import java.net.InetSocketAddress;
  2. import java.net.ServerSocket;
  3. import java.nio.ByteBuffer;
  4. import java.nio.CharBuffer;
  5. import java.nio.channels.ServerSocketChannel;
  6. import java.nio.channels.SocketChannel;
  7. import java.nio.charset.Charset;
  8. import java.nio.charset.CharsetDecoder;
  9.  
  10. /**
  11. * Created by LEESF on 2017/4/16.
  12. */
  13. public class ServerSocketChannelDemo {
  14. public static void main(String[] args) throws Exception {
  15. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  16. ServerSocket serverSocket = serverSocketChannel.socket();
  17. serverSocketChannel.configureBlocking(false);
  18. serverSocket.bind(new InetSocketAddress("localhost", 1234));
  19.  
  20. while (true) {
  21. SocketChannel socketChannel = serverSocketChannel.accept();
  22. if (socketChannel != null) {
  23. ByteBuffer byteBuffer = ByteBuffer.allocate(512);
  24. socketChannel.read(byteBuffer);
  25. byteBuffer.flip();
  26. System.out.println("server received message: " + getString(byteBuffer));
  27. byteBuffer.clear();
  28. String message = "server sending message " + System.currentTimeMillis();
  29. System.out.println("server sends message: " + message);
  30. byteBuffer.put(message.getBytes());
  31. byteBuffer.flip();
  32. socketChannel.write(byteBuffer);
  33. break;
  34. }
  35. }
  36. try {
  37. serverSocketChannel.close();
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. }
  41. }
  42.  
  43. public static String getString(ByteBuffer buffer) {
  44. Charset charset;
  45. CharsetDecoder decoder;
  46. CharBuffer charBuffer;
  47. try {
  48. charset = Charset.forName("UTF-8");
  49. decoder = charset.newDecoder();
  50. charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
  51. return charBuffer.toString();
  52. } catch (Exception ex) {
  53. ex.printStackTrace();
  54. return "";
  55. }
  56. }
  57. }

  客户端  

  1. import java.net.InetSocketAddress;
  2. import java.nio.ByteBuffer;
  3. import java.nio.CharBuffer;
  4. import java.nio.channels.SocketChannel;
  5. import java.nio.charset.Charset;
  6. import java.nio.charset.CharsetDecoder;
  7.  
  8. /**
  9. * Created by LEESF on 2017/4/16.
  10. */
  11. public class SocketChannelDemo {
  12. public static void main(String[] args) throws Exception {
  13. SocketChannel socketChannel = SocketChannel.open();
  14. socketChannel.connect(new InetSocketAddress("localhost", 1234));
  15. String message = "client sending message " + System.currentTimeMillis();
  16. ByteBuffer byteBuffer = ByteBuffer.allocate(512);
  17. byteBuffer.clear();
  18. System.out.println("client sends message: " + message);
  19. byteBuffer.put(message.getBytes());
  20. byteBuffer.flip();
  21. socketChannel.write(byteBuffer);
  22.  
  23. while (true) {
  24. byteBuffer.clear();
  25. int readBytes = socketChannel.read(byteBuffer);
  26. if (readBytes > 0) {
  27. byteBuffer.flip();
  28. System.out.println("client receive message: " + getString(byteBuffer));
  29.  
  30. break;
  31. }
  32. }
  33.  
  34. try {
  35. socketChannel.close();
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. }
  39. }
  40.  
  41. public static String getString(ByteBuffer buffer) {
  42. Charset charset;
  43. CharsetDecoder decoder;
  44. CharBuffer charBuffer;
  45. try {
  46. charset = Charset.forName("UTF-8");
  47. decoder = charset.newDecoder();
  48. charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
  49. return charBuffer.toString();
  50. } catch (Exception ex) {
  51. ex.printStackTrace();
  52. return "";
  53. }
  54. }
  55. }

  服务端结果如下 

  1. server received message: client sending message 1492334785236
  2. server sends message: server sending message 1492334785276

  客户端结果如下  

  1. client sends message: client sending message 1492334785236
  2. client receive message: server sending message 1492334785276

  每个DatagramChannel 对象关联一个DatagramSocket 对象,DatagramChannel 是模拟无连接协议(如 UDP/IP)。DatagramChannel 对象既可以充当服务器(监听者)也可以充当客户端(发送者)。如果新创建的通道负责监听,那么通道必须首先被绑定到一个端口或地址/端口组合上。  

  1. DatagramChannel channel = DatagramChannel.open( );
  2. DatagramSocket socket = channel.socket( );
  3. socket.bind (new InetSocketAddress (portNumber))

  2.7 管道

  管道就是一个用来在两个实体之间单向传输数据的导管,Pipe 类实现一个管道范例,不过它所创建的管道是进程内(在 Java 虚拟机进程内部)而非进程间使用的。Pipe 类创建一对提供环回机制的 Channel 对象。这两个通道的远端是连接起来的,以便任何写在 SinkChannel 对象上的数据都能出现在 SourceChannel 对象上。管道可以被用来仅在同一个 Java 虚拟机内部传输数据。

  当向管道中写入数据时,需要访问Pipe的sink通道,当从管道中读取数据时,需要访问Pipe的source通道,下面示例展示了通道的读写操作    

  1. import java.nio.ByteBuffer;
  2. import java.nio.CharBuffer;
  3. import java.nio.channels.Pipe;
  4. import java.nio.charset.Charset;
  5. import java.nio.charset.CharsetDecoder;
  6.  
  7. /**
  8. * Created by LEESF on 2017/4/16.
  9. */
  10.  
  11. public class PipeDemo {
  12. public static void main (String [] argv) throws Exception {
  13. Pipe pipe = Pipe.open();
  14. Pipe.SinkChannel sinkChannel = pipe.sink();
  15. String newData = "New String to write to file..." + System.currentTimeMillis();
  16. ByteBuffer buf = ByteBuffer.allocate(48);
  17. buf.clear();
  18. System.out.println("writing data: " + newData);
  19. buf.put(newData.getBytes());
  20. buf.flip();
  21. while (buf.hasRemaining()) {
  22. sinkChannel.write(buf);
  23. }
  24.  
  25. Pipe.SourceChannel sourceChannel = pipe.source();
  26. ByteBuffer byteBuffer = ByteBuffer.allocate(48);
  27. sourceChannel.read(byteBuffer);
  28. byteBuffer.flip();
  29. String strs = getString(byteBuffer);
  30. System.out.println("reading data: " + strs);
  31. }
  32.  
  33. public static String getString(ByteBuffer buffer) {
  34. Charset charset;
  35. CharsetDecoder decoder;
  36. CharBuffer charBuffer;
  37. try {
  38. charset = Charset.forName("UTF-8");
  39. decoder = charset.newDecoder();
  40. charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
  41. return charBuffer.toString();
  42. } catch (Exception ex) {
  43. ex.printStackTrace();
  44. return "";
  45. }
  46. }
  47. }

  运行结果 

  1. writing data: New String to write to file...1492332436279
  2. reading data: New String to write to file...1492332436279

  NIO还提供了通道工具类共使用,即可以通过java.nio.channels.Channels类创建通道等操作。

三、总结

  本篇博文讲解了通道,包括文件通道和套接字通道,以及通道与缓冲之间gather和scatter的操作,更多具体内容,有兴趣的读者可以查阅源代码进一步学习,也谢谢各位园友的观看~

【NIO】Java NIO之通道的更多相关文章

  1. Java NIO原理分析

    Java IO 在Client/Server模型中,Server往往需要同时处理大量来自Client的访问请求,因此Server端需采用支持高并发访问的架构.一种简单而又直接的解决方案是“one-th ...

  2. Java NIO 开篇

    一些很好的blog(待更新): 1.NIO入门 2.NIO.2 入门,第 1 部分: 异步通道 API I- 就是从硬盘到内存 O- 就是从内存到硬盘 一.阻塞IO 第一种方式:我从硬盘读取数据,然后 ...

  3. Java NIO系列1-概观

    Java NIO系列1-概观 Java NIO.中间的N你既可以理解为(new),也就是新的IO,相对于java1.5之前的IO它确实是新的;也可以理解为(no-blocking),也就是非阻塞的IO ...

  4. 【Java nio】java nio笔记

    缓冲区操作:缓冲区,以及缓冲区如何工作,是所有I/O的基础.所谓“输入/输出”讲的无非就是把数据移出货移进缓冲区.进程执行I/O操作,归纳起来也就是向操作系统发出请求,让它要么把缓冲区里的数据排干,要 ...

  5. java大文件读写操作,java nio 之MappedByteBuffer,高效文件/内存映射

    java处理大文件,一般用BufferedReader,BufferedInputStream这类带缓冲的Io类,不过如果文件超大的话,更快的方式是采用MappedByteBuffer. Mapped ...

  6. Java-杂项-java.nio:java.nio

    ylbtech-Java-杂项-java.nio:java.nio java.nio全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有 ...

  7. Java NIO全面详解(看这篇就够了)

    很多技术框架都使用NIO技术,学习和掌握Java NIO技术对于高性能.高并发网络的应用是非常关键的@mikechen NIO简介 NIO 中的 N 可以理解为 Non-blocking,不单纯是 N ...

  8. reactor模式与java nio

     Reactor是由Schmidt, Douglas C提出的一种模式,在高并发server实现中广泛採用. 改模式採用事件驱动方式,当事件出现时,后调用对应的事件处理代码(Event Handl ...

  9. JAVA NIO Socket通道

      DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...

  10. 转:Java NIO系列教程(五) 通道之间的数据传输

    在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel. transferFro ...

随机推荐

  1. python 全栈开发,Day65(索引)

    索引 一.索引的介绍 数据库中专门用于帮助用户快速查找数据的一种数据结构.类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置吗,然后直接获取. 二 .索引的作用 约束和加速查找 三.常 ...

  2. 委托Func和Action【转】

    平时我们如果要用到委托一般都是先声明一个委托类型,比如: private delegate string Say(); string说明适用于这个委托的方法的返回类型是string类型,委托名Say后 ...

  3. Ext.js入门:常用组件与综合案例(七)

    一:datefield简单示例 二:timefield简单示例 三:numberfield简单示例 四:FormPanel提交   datefield简单示例: <html xmlns=&quo ...

  4. Android 使用 SVG 矢量图

    android svg矢量图 可能包含的操作有: SVG图还包括改变颜色,透明度,大小,矩阵操作(平移.旋转.缩放),selector, (图标,背景,按钮),动画,等 setTint(int Col ...

  5. async/await套路编程

    对于并发任务,通常是用生成消费模型,对队列的处理可以使用类似master-worker的方式,master主要用户获取队列的msg,worker用户处理消息. 为了简单起见,并且协程更适合单线程的方式 ...

  6. 文档工具GitBook使用

    一.登陆注册 地址:https://www.gitbook.com/ 1.gitbook可使用github账号登录,如果已经注册github可以直接使用github账号登录 2.如果是github账号 ...

  7. 设置cookie,获取cookie,删除cookie,修改cookie

    怎么设置cookie,怎么设置cookie以及删除cookie和cookie详解 在操作cookie之前,先来看一下cookie长什么样. 可以看到,cookie是一个个键值对(“键=值”的形式)加上 ...

  8. Sea Battle CodeForces - 729D

    题意: 有n个格子,a条船,每条船占b个格子.事先已经射击了k个格子,且这k次射击不会射到船上,求再射击几次可以射到某一条船的某一部分 思路: 观察样例可以发现,如果五个0,船的长度是3,那么这五个0 ...

  9. POJ 1375 Intervals 光源投影【平面几何】

    <题目链接> <转载于> 题目大意: 给一个光源点s,给一些圆,源点和s相切会形成阴影,求每一段阴影在横轴上的区间. 解题分析: 这道其实不需要点与圆切线的板子来求解,完全可以 ...

  10. Luogu

    dalao们的博客a http://hzwer.com   //Orz  %%% https://oi-wiki.org  //Orz https://www.cnblogs.com/-guz/p/9 ...