java NIO

合肥-NIO蔚来汽车JAVA开发 面试一面电话二面视频(需要写代码)视频一视频二视频三 一面电话 时长:30分钟 实际:25分钟的样子 难度:一般 Nacos注册中心原理 从raft选举到pull、push整个流程 Dubbo调用原理 首先跟面试官说了dubbo怎么把服务注册到nacos中,再到从nacos中获取注册服务列表,调用的几种方式和负载均衡算法 Dubbo中3个消费者、4个提供者共建立了多少个连接 这个题回答了好久,主要是前面问了nacos,还以为dubbo跟nacos建立了多少链接,后面面试官说消费者和提供 阅读详情

基础概念

  • 缓冲区操作 
    缓冲区及操作是所有I/O的基础,进程执行I/O操作,归结起来就是向操作系统发出请求,让它要么把缓冲区里的数据排干(写),要么把缓冲区填满(读)。如下图QQ图片20130604164935
  • 内核空间、用户空间
    上图简单描述了数据从磁盘到用户进程的内存区域移动的过程,其间涉及到了内核空间与用户空间。这两个空间有什么区别呢?
    用户空间就是常规进程(如JVM)所在区域,用户空间是非特权区域,如不能直接访问硬件设备。内核空间是操作系统所在区域,那肯定是有特权啦,如能与设备控制器通讯,控制用户区域的进程运行状态。进程执行I/O操作时,它执行一个系统调用把控制权交由内核。
  • 虚拟内存
  • 内存页面调度

5种I/O模型

       说起I/O模型,网络上有一个错误的概念,异步非阻塞/阻塞模型,其实异步根本就没有阻不阻塞之说,异步模型就是异步模型。让我们来看一看Richard Stevens在其UNIX网络编程卷1中提出的5个I/O模型吧。

  • 阻塞式I/O

image

  • 非阻塞式I/O

image

  • I/O复用(Java NIO就是这种模型)

image

  • 信号驱动式I/O
  • 异步I/O

image

       由POSIX术语定义,同步I/O操作导致请求进程阻塞,直到I/O操作完成;异步I/O操作不导致请求进程阻塞。5种模型中的前4种都属于同步I/O模型。

Why NIO?

       开始讲NIO之前,了解为什么会有NIO,相比传统流I/O的优势在哪,它可以用来做什么等等的问题,还是很有必要的。

      传统流I/O是基于字节的,所有I/O都被视为单个字节的移动;而NIO是基于块的,大家可能猜到了,NIO的性能肯定优于流I/O。没错!其性能的提高要得益于其使用的结构更接近操作系统执行I/O的方式:通道和缓冲器。我们可以把它想象成一个煤矿,通道是一个包含煤层(数据)的矿藏,而缓冲器则是派送到矿藏的卡车。卡车载满煤炭而归,我们再从卡车上获得煤炭。也就是说,我们并没有直接和通道交互;我们只是和缓冲器交互,并把缓冲器派送到通道。通道要么从缓冲器获得数据,要么向缓冲器发送数据。(这段比喻出自Java编程思想)

      NIO的主要应用在高性能、高容量服务端应用程序,典型的有Apache Mina就是基于它的。

缓冲区
         
缓冲区实质上就是一个数组,但它不仅仅是一个数组,缓冲区还提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。为什么这么说呢?下面来看看缓冲区的细节。
          讲缓冲区细节之前,我们先来看一下缓冲区“家谱”:

buffer

  • 内部细节
        缓冲区对象有四个基本属性:
    • 容量Capacity:缓冲区能容纳的数据元素的最大数量,在缓冲区创建时设定,无法更改
    • 上界Limit:缓冲区的第一个不能被读或写的元素的索引
    • 位置Position:下一个要被读或写的元素的索引
    • 标记Mark:备忘位置,调用mark()来设定mark=position,调用reset()设定position=mark

      这四个属性总是遵循这样的关系:0<=mark<=position<=limit<=capacity。下图是新创建的容量为10的缓冲区逻辑视图:
                  image

     

  
buffer.put(( byte ) ' H ' ).put(( byte ) ' e ' ).put(( byte ) ' l ' ).put(( byte ) ' l ' ).put(( byte ) ' o ' );

      五次调用put后的缓冲区:
                  image
     

      

  
buffer.put( 0 ,( byte ) ' M ' ).put(( byte ) ' w ' );

      调用绝对版本的put不影响position:
                  image
      现在缓冲区满了,我们必须将其清空。我们想把这个缓冲区传递给一个通道,以使内容能被全部写出,但现在执行get()无疑会取出未定义的数据。我们必须将posistion设为0,然后通道就会从正确的位置开始读了,但读到哪算读完了呢?这正是limit引入的原因,它指明缓冲区有效内容的未端。这个操作在缓冲区中叫做翻转:buffer.flip()。
                   image
       rewind操作与flip相似,但不影响limit。


       将数据从输入通道copy到输出通道的过程应该是这样的:

               
  
while ( true ) { buffer.clear(); // 重设缓冲区以便接收更多字节 int r = fcin.read( buffer ); if (r ==- 1 ) { break ; } buffer.flip(); // 准备读取缓冲区数据到通道 fcout.write( buffer ); }
  • 创建缓冲区
           一般,新分配一个缓冲区是通过allocate方法的。如果你想提供自己的数组用做缓冲区的备份存储器,请调用wrap方法。
           上面两种方式创建的缓冲区都是间接的,间接的缓冲区使用备份数组(相关的方法有hasArray()、array()、arrayOffset())。
  • 复制缓冲区
           duplicate方法创建一个与原始缓冲区类似的缓冲区,两个缓冲区共享数据元素,不过它们拥有各自的position、limit、mark,如下图:
           image
           另一个方法,slice与duplicate相似,但slice方法创建一个从原始缓冲区的当前位置开始的新缓冲区,而且容量是原始缓冲区的剩余元素数量(limit-position),见下图。
           image
  • 字节缓冲区
    • 字节序
             为什么会有字节序?比如有1个int类型数字0x036fc5d9,它占4个字节 ,那么在内存中存储时,有可能其最高字节03位于低位地址(大端字节顺序),也有可能最低字节d9位于低位地址(小端字节顺序)。
             在IP协议中规定了使用大端的网络字节顺序,所以我们必须先在本地主机字节顺序和通用的网络字节顺序之间进行转换。java.nio中,字节顺序由ByteOrder类封装。
             在ByteBuffer中默认字节序为ByteBuffer.BIG_ENDIAN,不过byte为什么还需要字节序呢?ByteBuffer和其他基本数据类型一样,具有大量便利的方法用于获取和存放缓冲区内容,这些方法对字节进行编码或解码的方式取决于ByteBuffer当前字节序。
    • 直接缓冲区
             直接缓冲区是通过调用ByteBuffer.allocateDirect方法创建的。通常直接缓冲区是I/O操作的最好选择,因为它避免了一些复制过程;但可能也比间接缓冲区要花费更高的成本;它的内存是通过调用本地操作系统方面的代码分配的。
    • 视图缓冲区
             视图缓冲区和缓冲区复制很像,不同的只是数据类型,所以字节对应关系也略有不同。比如ByteBuffer.asCharBuffer,那么转换后的缓冲区通过get操作获得的元素对应备份存储中的2个字节。
    • 如何存取无符号整数?
             Java中并没有直接提供无符号数值的支持,每个从缓冲区读出的无符号值被升到比它大的下一个数据类型中。
            
            
      public static short getUnsignedByte(ByteBuffer bb) { return (( short ) (bb.get() & 0xff )); } public static void putUnsignedByte(ByteBuffer bb, int value) { bb.put(( byte ) (value & 0xff )); }

通道

        通道用于在缓冲区和位于通道另一侧的实体(文件、套接字)之间有效的传输数据。相对于缓冲区,通道的“家谱”略显复杂:

channel 

  • 使用通道
           打开通道比较简单,除了FileChannel,都用open方法打开。
           我们知道,通道是和缓冲区交互的,从缓冲区获取数据进行传输,或将数据传输给缓冲区。从类继承层次结构可以看出,通道一般都是双向的(除FileChannel)。
           下面来看一下通道间数据传输的代码:
          
        
    private static void channelCopy(ReadableByteChannel src, WritableByteChannel dest) throws IOException { ByteBuffer buffer = ByteBuffer.allocateDirect( 16 * 1024 ); while (src.read(buffer) != - 1 ) { // Prepare the buffer to be drained buffer.flip(); // Write to the channel; may block dest.write(buffer); // If partial transfer, shift remainder down // If buffer is empty, same as doing clear( ) buffer.compact(); } // EOF will leave buffer in fill state buffer.flip(); // Make sure that the buffer is fully drained while (buffer.hasRemaining()) { dest.write(buffer); } }
  • 关闭通道
           通道不能被重复使用,这点与缓冲区不同;关闭通道后,通道将不再连接任何东西,任何的读或写操作都会导致ClosedChannelException。
           调用通道的close()方法时,可能会导致线程暂时阻塞,就算通道处于非阻塞模式也不例外。如果通道实现了InterruptibleChannel接口,那么阻塞在该通道上的一个线程被中断时,该通道将被关闭,被阻塞线程也会抛出ClosedByInterruptException异常。当一个通道关闭时,休眠在该通道上的所有线程都将被唤醒并收到一个AsynchronousCloseException异常。
  • 发散、聚集
           发散、聚集,又被称为矢量I/O,简单而强大的概念,它是指在多个缓冲区上实现一个简单的I/O操作。它减少或避免了缓冲区的拷贝和系统调用,它应该使用直接缓冲区以从本地I/O获取最大性能优势。
  • 文件通道
  • Socket通道
           Socket通道有三个,分别是ServerSocketChannel、SocketChannel和DatagramChannel,而它们又分别对应java.net包中的Socket对象ServerSocket、Socket和DatagramSocket;Socket通道被实例化时,都会创建一个对等的Socket对象。
           Socket通道可以运行非阻塞模式并且是可选择的,非阻塞I/O与可选择性是紧密相连的,这也正是管理阻塞的API要在SelectableChannel中定义的原因。设置非阻塞非常简单,只要调用configureBlocking(false)方法即可。如果需要中途更改阻塞模式,那么必须首先获得blockingLock()方法返回的对象的锁。
    • ServerSocketChannel
             ServerSocketChannel是一个基于通道的socket监听器。但它没有bind()方法,因此需要取出对等的Socket对象并使用它来绑定到某一端口以开始监听连接。在非阻塞模式下,当没有传入连接在等待时,其accept()方法会立即返回null。正是这种检查连接而不阻塞的能力实现了可伸缩性并降低了复杂性,选择性也因此得以实现。
            
            
      ByteBuffer buffer = ByteBuffer.wrap( " Hello World " .getBytes()); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind( new InetSocketAddress( 12345 )); ssc.configureBlocking( false ); for (;;) { System.out.println( " Waiting for connections " ); SocketChannel sc = ssc.accept(); if (sc == null ) TimeUnit.SECONDS.sleep( 2000 ); else { System.out.println( " Incoming connection from: " + sc.socket().getRemoteSocketAddress()); buffer.rewind(); sc.write(buffer); sc.close(); } }
    • SocketChannel
             相对于ServerSocketChannel,它扮演客户端,发起到监听服务器的连接,连接成功后,开始接收数据。
             要注意的是,调用它的open()方法仅仅是打开但并未连接,要建立连接需要紧接着调用connect()方法;也可以两步合为一步,调用open(SocketAddress remote)方法。
             你会发现connect()方法并未提供timout参数,作为替代方案,你可以用isConnected()、isConnectPending()或finishConnect()方法来检查连接状态。
    • DatagramChannel
             不同于前面两个通道对象,它是无连接的,它既可以作为服务器,也可以作为客户端。

选择器

       选择器提供选择执行已经就绪的任务的能力,这使得多元I/O成为可能。就绪选择和多元执行使得单线程能够有效率地同时管理多个I/O通道。选择器可谓NIO中的重头戏,I/O复用的核心,下面我们来看看这个神奇的东东。

  • 基础概念
           我们先来看下选择器相关类的关系图:
           selector 
           由图中可以看出,选择器类Selector并没有和通道有直接的关系,而是通过叫选择键的对象SelectionKey来联系的。选择键代表了通道与选择器之间的一种注册关系,channel()和selector()方法分别返回注册的通道与选择器。由类图也可以看出,一个通道可以注册到多个选择器;注册方法register()是放在通道类里,而我感觉放在选择器类里合适点。
           非阻塞特性与多元执行的关系非常密切,如果在阻塞模式下注册一个通道,系统会抛出IllegalBlockingModeException异常。
           那么,通道注册到选择器后,选择器又是如何实现就绪选择的呢?真正的就绪操作是由操作系统来做的,操作系统处理I/O请求并通知各个线程它们的数据已经准备好了,而选择器类提供了这种抽象。
           选择键作为通道与选择器的注册关系,需要维护这个注册关系所关心的通道操作interestOps()以及通道已经准备好的操作readyOps(),这两个方法的返回值都是比特掩码,另外ready集合是interest集合的子集。选择键类中定义了4种可选择操作:read、write、connect和accept。类图中你可以看到每个可选择通道都有一个validOps()的抽象方法,每个具体通道各自有不同的有效的可选择操作集合,比如ServerSocketChannel的有效操作集合是accept,而SocketChannel的有效操作集合是read、write和connect。
           回过头来再看下注册方法,其第二个参数是一个比特掩码,这个参数就是上面讲的这个注册关系所关心的通道操作。在选择过程中,所关心的通道操作可以由方法interestOps(int operations)进行修改,但不影响此次选择过程(在下一次选择过程中生效)。
  • 使用选择器
    • 选择过程
             类图中可以看出,选择器类中维护着两个键的集合:已注册的键的集合keys()和已选择的键的集合selectedKeys(),已选择的键的集合是已注册的键的集合的子集。已选择的键的集合中的每个成员都被选择器(在前一个选择操作中)判断为已经准备好(所关心的操作集合中至少一个操作)。 除此之外,其实选择器内部还维护着一个已取消的键的集合,这个集合包含了cancel()方法被调用过的键。
             选择器类的核心是选择过程,基本上来说是对select()、poll()等系统调用的一个包装。那么,选择过程的具体细节或步骤是怎样的呢?
             当选择器类的选择操作select()被调用时,下面的步骤将被执行:
             1.已被取消的键的集合被检查。如果非空,那么该集合中的键将从另外两个集合中移除,并且相关通道将被注销。这个步骤结束后,已取消的键的集合将为空。
             2.已注册的键的集合中的键的interest集合将被检查。在这个步骤执行过后,对interset集合的改动不会影响剩余的检查过程。一旦就绪条件被确定下来,操作系统将会进行查询,以确定每个通道所关心的操作的真实就绪状态。这可能会阻塞一段时间,最终每个通道的就绪状态将确定下来。那些还没有准备好的通道将不会执行任何操作;而对于那些操作系统指示至少已经准备好interest集合中的一个操作的通道,将执行以下两种操作中的一种:
             a.如果通道的键还没有在已选择的键的集合中,那么键的ready集合将被清空,然后表示操作系统发现的当前通道已经准备好的操作的比特掩码将被设置。
             b.如果通道的键已处于已选择的键的集合中,键的ready集合将被表示操作系统发现的当前通道已经准备好的操作的比特掩码所更新,所有之前的已经不再是就绪状态的操作不会被清除。
             3.步骤2可能会花费很长时间,特别是调用的线程处于休眠状态。同时,与选择器相关的键可能会被取消。当步骤2结束时,步骤1将重新执行,以完成任意一个在选择过程中,键已经被取消的通道的注销。
             4.select操作返回的值是ready集合在步骤2中被修改的键的数量,而不是已选择键的集合中的通道总数。返回值不是已经准备好的通道的总数,而是从上一个select调用之后进入就绪状态的通道的数量。之前调用中就绪的,并且在本次调用中仍然就绪的通道不会被计入。
    • 停止选择过程 
             选择器类提供了方法wakeup(),可以使线程从被阻塞的select()方法中优雅的退出,它将选择器上的第一个还没有返回的选择操作立即返回。
             调用选择器类的close()方法,那么任何一个阻塞在选择过程中的线程将被唤醒,与选择器相关的通道将被注销,而键将被取消。
             另外,选择器类也能捕获InterruptedException异常并调用wakeup()方法。
    • 并发性
  • 选择过程的可扩展性
           在单cpu中使用一个线程为多个通道提供服务可能是个好主意,但对于多cpu的系统,单线程必然比多线程在性能上要差很多。
           一个比较不错的多线程策略是,以所有的通道使用一个选择器(或多个选择器,视情况),并将以就绪通道的服务委托给其他线程。用一个线程监控通道的就绪状态,并使用一个工作线程池来处理接收到的数据。

       讲了这么多,下面来看一段用NIO写的简单服务器代码:
      

  
private void run( int port) throws IOException { // Allocate buffer ByteBuffer echoBuffer = ByteBuffer.allocate( 1024 ); // Create a new selector Selector selector = Selector.open(); // Open a listener on the port, and register with the selector ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking( false ); ServerSocket ss = ssc.socket(); InetSocketAddress address = new InetSocketAddress(port); ss.bind(address); SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT); System.out.println( " Going to listen on " + port); for (;;){ int num = selector.select(); Set selectedKeys = selector.selectedKeys(); Iterator it = selectedKeys.iterator(); while (it.hasNext()) { SelectionKey selectionKey = (SelectionKey) it.next(); if ((selectionKey.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) { // Accept the new connection ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel(); SocketChannel sc = serverSocketChannel.accept(); sc.configureBlocking( false ); // Add the new connection to the selector SelectionKey newKey = sc.register(selector, SelectionKey.OP_READ); it.remove(); System.out.println( " Got connection from " + sc); } else if ((selectionKey.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) { // Read the data SocketChannel sc = (SocketChannel) selectionKey.channel(); // Echo data int bytesEchoed = 0 ; while ( true ) { echoBuffer.clear(); int r = sc.read(echoBuffer); if (r <= 0 ) { break ; } echoBuffer.flip(); sc.write(echoBuffer); bytesEchoed += r; } System.out.println( " Echoed " + bytesEchoed + " from " + sc); it.remove(); } } } }
     

I/O多路复用模式

       I/O多路复用有两种经典模式:基于同步I/O的reactor和基于异步I/O的proactor。 

  • Reactor
    • 某个事件处理者宣称它对某个socket上的读事件很感兴趣;
    • 事件分离者等着这个事件的发生;
    • 当事件发生了,事件分离器被唤醒,这负责通知先前那个事件处理者;
    • 事件处理者收到消息,于是去那个socket上读数据了. 如果需要,它再次宣称对这个socket上的读事件感兴趣,一直重复上面的步骤;
  • Proactor
    • 事件处理者直接投递发一个写操作(当然,操作系统必须支持这个异步操作). 这个时候,事件处理者根本不关心读事件,它只管发这么个请求,它魂牵梦萦的是这个写操作的完成事件。这个处理者很拽,发个命令就不管具体的事情了,只等着别人(系统)帮他搞定的时候给他回个话。
    • 事件分离者等着这个读事件的完成(比较下与Reactor的不同);
    • 当事件分离者默默等待完成事情到来的同时,操作系统已经在一边开始干活了,它从目标读取数据,放入用户提供的缓存区中,最后通知事件分离者,这个事情我搞完了;
    • 事件分享者通知之前的事件处理者: 你吩咐的事情搞定了;
    • 事件处理者这时会发现想要读的数据已经乖乖地放在他提供的缓存区中,想怎么处理都行了。如果有需要,事件处理者还像之前一样发起另外一个写操作,和上面的几个步骤一样。

       异步的proactor固然不错,但它局限于操作系统(要支持异步操作),为了开发真正独立平台的通用接口,我们可以通过reactor模拟来实现proactor。

  • Proactor(模拟)
    • 等待事件 (Proactor 的工作)
    • 读数据(看,这里变成成了让 Proactor 做这个事情)
    • 把数据已经准备好的消息给用户处理函数,即事件处理者(Proactor 要做的)
    • 处理数据 (用户代码要做的)

总结

       本文介绍了I/O的一些基础概念及5种I/O模型,NIO是5种模型中的I/O复用模型;接着进入主题Java NIO,分别讲了NIO中三个最重要的概念:缓冲区、通道、选择器;我们也明白了NIO是如何实现I/O复用模型的。最后讨论了I/O多路复用模式中的两种模式:reactor和proactor,以及如何用reactor模拟proactor。

java NIO及NIO聊天室 参考链接: java NIO实例1:http://blog.chinaunix.net/uid-25808509-id-3346228.html java NIO教程之selector(一系列):http://ifeve.com/selectors/ java NIO与IO的比较:http://blog.youkuaiyun.com/keda8997110/article/details/19549 阅读详情

相关推荐

从单机到多机:用llama.cpp的RPC模式榨干你闲置的GPU(附性能调优参数)

本文详细介绍了如何利用llama.cpp的RPC模式实现多机部署,将闲置GPU资源整合为高效推理集群。通过实战案例展示了性能调优参数设置、端口分配策略以及常见问题排查技巧,帮助中小团队最大化利用异构GPU设备,提升文本摘要等任务的推理效率。

weixin_27240351的博客 590

java.nio.channels.IllegalBlockingModeException

java.nio.channels.IllegalBlockingModeException 相关错误代码: [java]view plaincopy classHandler{ publicHandler(Selectorselector,SocketChannelsocketChannel)...

weixin_33906657的博客 806

[VisionPro] CogPMAlignTool 工具详解

[VisionPro] [CogPMAlignTool] [模板匹配]

weixin_43163656的博客 1万+

Androin学习笔记四十三:Socket(示例,出错代码)

出处:http://www.apihome.cn/api/java/Socket.html java.net 类 Socket java.lang.Object java.net.Socket 直接已知子类:SSLSocket public class Socketextends Object 此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器

自由的天空 1564

基于STM32L4XX、HAL库的AD7768BSTZ 模数转换器ADC驱动程序设计

/ 默认SPI配置。// 读取通道数据命令。// 通过SYNC_IN引脚触发转换(如果使用)// 处理数据...// 或者通过SPI命令。// 初始化AD7768。// SPI1引脚配置。

zhusl6688的博客 462

(持续更新中!)详解【计算机类&面试真题】军队文职考试 ——第一期(真题+解析)| TCP、UDP的区别;程序局部性;ICMP协议及主要功能;重定位所需的计算机硬件

在当今信息化时代,军队中对于计算机专业人才的需求与日俱增。因此,了解面试和复试中常见的问题和要求对于准备应聘者来说至关重要。本文将围绕面试的准备要点、常见问题以及面试技巧进行探讨,并提供一些建议和经验。通过了解面试和复试的准备要点、常见问题以及技巧,读者将能够提升应对能力和成功率。本文为准备军队文职面试和计划考研复试的读者提供了有价值的参考和指导。通过阅读本篇博客,读者将能够获得关于军队文职计算机类面试和计算机考研复试的全面了解,提升自身的应对能力和成功率。

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 1690

Java中NIO报错Exception in thread “main“ java.nio.channels.IllegalBlockingModeException

异常信息 Exception in thread "main"java.nio.channels.IllegalBlockingModeException 当使用Java中NIO时,如果爆出上述异常,就说明对应的Channel没有配置configureBlocking(false),也就是将Channel获取数据变为非阻塞。

qq_40276626的博客 1652

【某音电商】protobuf聊天协议逆向

某音电商私信、聊天消息protobuf协议逆向分析与解析

吴秋霖的博客 2315

理解Java NIO

转载:http://my.oschina.net/regulusun/blog/137819 基础概念 缓冲区操作  缓冲区及操作是所有I/O的基础,进程执行I/O操作,归结起来就是向操作系统发出请求,让它要么把缓冲区里的数据排干(写),要么把缓冲区填满(读)。如下图 内核空间、用户空间 上图简单描述了数据从磁盘到用户进程的内存区域移动的过程,其间涉及到了内核空间与用户空间。这两个...

decision06的专栏 182

【系统分析师】写作框架:软件设计模式及其应用

本文围绕"软件设计模式及其应用"展开论述。首先介绍了近三年参与的某软件开发项目背景及个人承担的系统设计工作。其次系统阐述了设计模式的三大分类:创建型(如工厂方法、单例模式)、结构型(如适配器、装饰器模式)和行为型(如观察者、策略模式),重点分析了各类模式的特点和典型应用场景。最后结合项目实践,详细说明了采用的三种设计模式的具体实施过程及效果,包括提高代码复用性、降低耦合度等优势。文章还总结了项目经验,指出存在的不足及改进方向,强调合理运用设计模式对构建高质量软件系统的重要性。全文通过理论

数据知道的博客 5061

Python 爬虫实战:全国高校录取分数线数据爬取与院校对比分析

本文介绍了一个基于Python的高考志愿填报辅助系统,通过爬取掌上高考平台的全国高校录取分数线数据,构建本地数据库并实现智能分析。系统主要功能包括:1)使用requests+BeautifulSoup爬取院校基本信息和历年分省分科类录取线;2)通过SQLite实现数据持久化与增量更新;3)利用pyecharts生成分数线趋势图、院校对比雷达图等可视化图表;4)提供"冲稳保"三档智能选校推荐。技术栈涵盖网络爬虫、数据清洗、数据库管理和可视化分析,可为考生提供数据驱动的志愿填报决策支持。项目采用模块化设计,包含

u014481728的博客 238

JAVA NIO详解

1. IO 和 NIO 相关的预备知识 1.1 IO 的含义 讲 NIO 之前,我们先来看一下 IO。 Java IO 即 Java 输入输出。在开发应用软件时,很多时候都需要和各种输入输出相关的媒介打交道。与媒介进行 IO 操作的过程十分复杂,需要考虑众多因素,比如:进行 IO 操作媒介的类型(文件、控制台、网络)、通信方式(顺序、随机、二进制、按字符、按字、按行等等)。 Java 类库提供了相...

努力奔跑 2万+

【气候极端指数】MATLAB计算各种气候极端指数

简介各类气候极端指数,及其MATLAB计算代码

WW、forever的博客 4917

【蔚来汽车日常实习】蔚来汽车Java后端实习

【蔚来汽车日常实习】蔚来汽车Java后端实习

qq_44653420的博客 1619

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

java nio 详_java NIO 详解

Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。本系列教程将有助于你学习和理解Java NIO。Java NIO提供了与标准IO不同的IO工作方式:Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总...

weixin_35282700的博客 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java NIO详解

JAVA NIO 简介 NIO与IO的对比

代码充实生活的博客 1万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java NIO真得就这么简单

Java NIO真得就这么简单 大多数人肯定了解Java IO, 但是对于NIO一般是陌生的,但是Java NIO是一个高频知识点,又不得不学,所以本文通过图文+代码的方式,保姆级别的讲述Java NIO的各个知识点。觉得写得好的,希望点个赞,给个收藏。 Java IO 与 Java NIO的区别 Java IO 与 Java NIO读取文件的差别 普通Java IO public static void ioReadFile(String fileName) throws Exception {

zycxnanwang的博客 2599

Java NIO 总结: NIO技术基础回顾

Java NIO是Java 1.4版本引入的一套新的IO API,它提供了非阻塞IO操作的功能,支持面向缓冲区的、基于通道的IO操作。Java NIO的核心组件包括Channels、Buffers和Selectors。

码到三十五 1560

Java NIO 详解

前言 本篇将分为BIO、NIO概念介绍、javaNIO组件、并发NIO简易模型实例三部分组成,为读者和我自己增加对NIO的理解。 一、概念认知 这里主要是介绍NIO,但是在介绍NIO的时候难免会提到BIO,所以这里也顺带介绍一下什么是BIO,由此切入NIO。 1 什么是IO 在介绍BIO之前先来了解一下更加普遍的概念IO,IO是输入流和输出流的统称,在IO的世界里,有几个重要的概念,分别是同步、异步、阻塞、非阻塞,在这一小部分主要也是介绍这四个的概念。 同步与异步 同步异步中有一个主线程的概念问题,就是当前

Burnup_110的博客 3290

Java NIO使用

Java NIO 概念 Java NIO(New IO),No Blocking IO 非阻塞IO,是从Java1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的,基于通道的IO操作。NIO将以更加高效的方式进行文件读写操作 IO和NIO的区别 IO NIO 面向流(Stream Oriented) 面向缓冲区(Buffer Oriented) 阻塞IO(Blocking I

Hai-Yang-code的博客 6604

nio java是什么_JAVA NIO是什么(zz)

JAVA NIO是什么?1.基本概念IO 是主存和外部设备 ( 硬盘、终端和网络等 ) 拷贝数据的过程。 IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成。所有语言运行时系统提供执行 I/O 较高级别的工具。 (c 的 printf scanf,java 的面向对象封装 )2.Java标准 io回顾Java 标准 IO 类库是 io 面向对象的一种抽象。基于本地方法的底层实现,...

weixin_34828613的博客 2708

java nio_什么是JAVA NIO

NIO(Non-Blocking I/O,java中,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,是解决高并发、I/O处理问题的有效方式。一、传统的BIOBIO(Blocking I/O)即同步阻塞I/O,在NIO出现之前主要使用BIO及新建线程的方式来解决并发请求,但这样很容易因线程瓶颈而造成限制。下面是BIO的经典编程模...

weixin_33838871的博客 239

java当中什么是NIO

Java NIO作为一种高效的I/O处理方式,特别适合于需要处理大量并发连接的场景。通过使用通道、缓冲区和选择器,NIO在提供非阻塞I/O操作的同时,也提供了灵活的数据处理能力。尽管NIO的编程模型比传统的BIO更为复杂,但在高并发、高性能的应用中,NIO无疑是一个值得选择的解决方案。随着Java的发展,NIO已经成为Java生态中不可或缺的重要组成部分,未来它在高性能计算和并发处理领域将继续发挥重要作用。

Flying_Fish_roe的博客 2612

java nio书籍_《Java NIO》这本书

这两天花了时间学习了java的nio,看的书是Ron Hitchens著的 《Java NIO》,总的来说,这本书真的写的非常好,而且整本书将java nio的内容从底层讲了个遍,书不厚,但是确实值得一读,这里总结一下学习后的一些心得。学习过程中既详细看完了《Java NIO》这本书,同时也参照了http://zhangshixi.iteye.com/blog/679959该作者写的关于NIO的博...

weixin_39914868的博客 1517

Java NIO(一):认识NIO

本文介绍了Java NIO的核心概念与应用场景。NIO通过缓冲区、通道和选择器三大组件,解决了传统IO在高并发和大数据量传输时的性能瓶颈。文章对比了BIO与NIO的差异,详细解析了Buffer的工作原理和Channel类型,并举例说明了Selector在多路复用中的优势。通过文件拷贝的代码示例展示了NIO的实际应用,同时从直接内存和零拷贝两方面解释了NIO的性能优势。最后指出BIO适用于简单场景,而NIO更适合高并发网络应用,并建议网络编程优先使用Netty框架而非原生NIO。全文系统性地阐述了NIO的核心

欧阳方超的专栏 1147
上一篇: 数据科学家应该具备的知识
下一篇: 字节流与字符流的区别
faadfafasd
博客等级 码龄12年 14粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值