`
wx1568520008
  • 浏览: 20399 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

最近仔细研究了一下Java的NIO以及线程并发,搞清了点思路,特作笔记如下(NIO篇)...

 
阅读更多

同类文章:

http://weixiaolu.iteye.com/blog/1479656

 

   因为前段时间的项目需要写一些高性能服务器,结果写出来的结果是五花八门,我们要求使用NIO编写异步服务器,但是竟然有人把NIO硬生生地写成同步的,还写成了一个单道批处理,线程调度、通信、同步操作,尤如天马行空,看不出一点架构,典型的面条代码,极度晕倒,不得不下定决心,将IO部分与线程调度部分隔离出来。
        为此,狠下心来,仔细研究了一下nio机制和dl的util.concurrent包。

一、NIO的出现
        NIO是JDK1.4里面才出现的东东,他给大家带来的最大好处是异步socket。其它file,pipe暂时就不多谈了。
        在JDK1.4出现之前,如果你需要编写一个Java服务器,为了实现异步操作,你必须为每个连接请求生成一个Java线程,当连接请求很多时,线程的调度,上下文切换,所付出的代价是非常昂贵,而且由于Java是跨平台的,各个平台对线程的支持并不相同,性能也不相同,因此传统的Java服务器编程架构是低效的且代价贵,dl大侠写了个util.concurrent包后,总算是减轻了线程调度给java程序员带来的痛苦,但是相比之与C、C++写出来的服务器,java服务器在性能要求很高的情况下,基本上没有什么竞争力,甚至是入围的权利的都没有。

二、异步socket的实现
       NIO出现后,好像让java的程序员有了杨眉吐气的机会,怎么个吐气法,当时大家是个什么感受,俺是不知道,因为当时俺不搞java,对java的认识有限。
       NIO是一个基于事件的IO架构,最基本的思想就是:有事件我通知你,你再去做你的事情,没事件时你大可以节约大把时间去做其它任何事情。而且NIO的主线程only one,不像传统的模型,需要N个线程去,也减轻了JVM的工作量,使得JVM处理任务时显得更加高效。
       刚开始接触NIO时,被N层的Channel架构、网上铺天盖地的好评给镇住了,想想也应当是个很成熟的产品了,网上资料这么多,抄一抄Jetty、Tomcat以及其它一些牛B的源代码,基本上就能搞定了,此时没有想到大家受同步的影响这么深,也没有想到连最基本的异步概念都没有搞清楚就去写代码,搞出一堆的问题来(这是后话,后面再说)。
       现在研究了NIO以后,发现NIO实际上在Java中做的工作是很简单,就是将事件进行收集和分发,我们结合一个经典的调用例子来说明这个问题,我就不从NIO的基本使用说起了,大家可以查其它的资料,网上一大把。
        当Channel注册至Selector以后,我们的最经典的调用方法,是这样子的。
        

 121213023_IkCe.gifwhile(somecondition)
 221213023_mwNk.gif{
 321213023_ZKsn.gif        int n = selector.select(TIMEOUT);
 421213023_ZKsn.gif        if(n == 0) continue;
 521213023_ZKsn.gif        for (Iterator iter = selector.selectedKeys().iterator(); iter.hasNext();)
 621213023_HhXD.gif        {
 721213023_ZKsn.gif        if (key.isAcceptable())
 821213023_ZKsn.gif            doAcceptable(key);
 921213023_ZKsn.gif        if (key.isConnectable())
1021213023_ZKsn.gif            doConnectable(key);
1121213023_ZKsn.gif        if (key.isValid() && key.isReadable())
1221213023_ZKsn.gif            doReadable(key);
1321213023_ZKsn.gif        if (key.isValid() && key.isWritable())
1421213023_ZKsn.gif            doWritable(key);
1521213023_ZKsn.gif      iter.remove();
1621213023_dmAu.gif    }
1721213023_z7cx.gif}

            这只是个小例子啊,什么异常我就懒得抓了。
            nio中取得事件通知,就是在selector的select事件中完成的,在selector事件时有一个线程,这个线程具体的处理简单点说就是:向操作系统询问,selector中注册的Channel&&SelectionKey的偶对各种事件是否有发生,如果有则添加到selector的selectedKeys属性Set中去,并返回本次有多少个感兴趣的事情发生。程序员发现这个值>0,表示有事件发生,马上迭代selectedKeys中的SelectionKey,根据Key中的表示的事件,来做相应的处理。
            实际上,这段说明表明了异步socket的核心,即异步socket不过是将多个socket的调度(或者还有他们的线程调度)全部交给操作系统自己去完成,异步的核心Selector,不过是将这些调度收集、分发而已。因为操作系统的socket、线程调度再咋D也比你JVM中要强,效率也高。
            而且就算jvm做的和操作系统一样好,性能一样高(当然这是不现实的),使用异步socket你至少也节约了一半的系统消耗,想想假定操作系统本身也是使用线程来维护N个socket连接,在传统的java编程中,你还必须为这些socket还多起一个java线程,那至少是2N个线程,现在只需要N+1。在高并发的情况下,你自己去想吧。
        懂了这个道理,异步socket也就好写了,也不会搞得思路混乱了。

三、 异步Socket中应当注意的事情
    3.1 读
          异步socket最基本的理念就是事件通知,前面也说了,有事件通知你了,你才该做你应当做的事情。在异步socket中当注册了一个OP_READ事件后,你就等着Selector通知你吧,如果没有通知你,你在家睡大觉都行。
         在这里,我们有人出现的错误就是受同步的影响,自己去主动读,而且还搞出了多线程,如果仔细考虑一下,就不会出现这个问题了。同步socket中,调用read方法读取IO中的数据时,通常情况下如果没有数据read方法会阻塞,且是同步的,所以当多个线程同时访问时,read方法是线程安全的。
         而在异步下就不同,异步是不会阻塞的,有什么就返回什么,你主动去读,只要有数据,你就可以拿走,在多线程的情况下,也许你是想让第一个线程读取,but此时来数据时正好是线程2读到了,那线程2就高高兴兴的拿去,而线程1还在苦苦等待,这样导致数据混乱不说,如果后面再也不来数据了,线程1就是死循环啦。

        2. 写
        在异步socket中,写是唯一一个主动点的操作,但是也不能直接去写Channel,而是应当先把自身注册为OP_WRITABLE,这时Selector就会发现你的存在,并把给发一个write事件,你这时后就可以写了,不过这时候有个小小的技巧,就是你执行写操作之前,请取消掉你的写注册,否则你的cpu肯定是100%。

        3. 等待
        在传统的服务器编程中,由于对于每个请求都是产生的一个线程,因此你在你每个请求线程中wait也好,sleep也好,不会影响别人。但是异步不同,他的主线程只有一个,基本上每个处理都是线性的,也就是说处理完第一个,然后才能处理第二个,因此nio是一个极好的处理短连接的架构。
        我们现在出现的问题是,有人受同步的影响,没有搞清异步是如何处理,竟然在方法处理中用上sleep,而且一等还是3秒,这意味着什么,3秒才能处理一个请求,My god,我要一个3秒才能处理一个请求的服务器干嘛啊,还是60年代啊:(
        如果出现这样的需要等待的情况,应当另起一个线程(推荐使用线程池)去完成这个“长”时间的任务,或者将其它交给一个消息队列,通过发消息的方式将给别人去完成也行,客户端能等,你服务器怎么也能等呢?写出这样的代码,基本上一个服务器也就废了。

        这blog我发在个人的心情随笔中,发点牢骚,实在是觉得对于有些人的思路觉得有些不可思议,不吐不快。

转载于:https://my.oschina.net/u/2365905/blog/1576985

分享到:
评论

相关推荐

    NIO笔记.doc

    Java NIO(New Input/Output)是Java标准库中提供的一种替代传统IO(基于流的I/O)模型的机制,其设计目标是为了提高程序在处理I/O操作时的性能。NIO的核心概念主要包括通道(Channel)、缓冲区(Buffer)和选择器...

    JAVA NIO学习笔记.docx

    import java.nio.channels.FileChannel; public class CopyFile { public static void main(String[] args) throws Exception { String infile = "C:\\copy.sql"; String outfile = "C:\\copy.txt"; ...

    nio demo for nio学习笔记(体系结构以及模块介绍)

    Java NIO库提供了多种实现,如`java.nio.channels`包下的各种Channel和Selector类,以及`java.nio`包下的Buffer类。 在学习NIO时,首先需要理解Channel、Buffer、Selector的基本概念和使用方法,然后通过实例来熟悉...

    java NIO学习系列 笔记

    Java NIO(New Input/Output)是Java标准库在JDK 1.4版本中引入的一个新特性,它提供了一种不同于传统IO流的高效I/O处理方式。NIO的核心概念包括通道(Channel)和缓冲区(Buffer),这两个组件使得数据以块的形式...

    java高并发笔记.docx

    【Java高并发笔记】 在Java开发中,处理高并发场景是一项关键技能,涉及到多个核心概念。以下是关于同步、异步、并发、并行、临界区、阻塞、非阻塞以及死锁、饥饿和活锁的详细解释。 1. **同步与异步** - **同步*...

    javaNIO学习笔记

    ### Java NIO 学习笔记 #### 一、概述 Java NIO (Non-Blocking IO,也称为 Java New IO),是 Java 对传统 IO 模型的一次重大改进,旨在提高程序处理大量并发连接的能力。NIO 的核心组件包括 Channels、Buffers 和 ...

    java黑马笔记.rar.rar

    多线程是并发编程的基础,Java提供了Thread类和Runnable接口来实现多线程。笔记会解释如何创建和管理线程,以及同步机制如synchronized关键字和wait/notify机制。 IO流和NIO(非阻塞I/O)是Java处理输入输出的重要...

    java入门笔记.pdf

    Java入门笔记文档详细阐述了Java编程语言的基本概念、开发工具、编程基础、面向对象编程、多线程、集合框架、IO流、网络编程、安全加密、反射机制、新特性、内存管理等多个方面,为初学者提供了一条通往Java编程世界...

    javaNIO学习笔记(csdn)————程序.pdf

    Java NIO,全称Non-Blocking Input/Output,是非阻塞式输入输出,它是Java从1.4版本开始引入的一种新的I/O模型,为Java程序员提供了处理I/O操作的新方式。NIO的主要特点是其能够使Java程序以更有效的方式处理I/O流,...

    JAVA NIO 聊天室程序

    在Java编程领域,网络编程是一个重要的部分,而NIO(Non-blocking Input/Output)是Java提供的一种高效、非阻塞的I/O模型,它极大地提升了处理大量并发连接的能力。这个"JAVA NIO 聊天室程序"是一个实践项目,旨在...

    JAVA课程学习笔记.doc

    本篇学习笔记将深入解析Java线程池的框架、结构、原理以及相关源码,帮助读者全面理解线程池的工作机制。 1. 线程池模块结构 线程池框架分为多层结构,其中包括核心实现类、辅助类和接口等组件。例如,`sun.nio.ch....

    Java《剑指Offer》刷题笔记.zip

    5. **并发编程**:掌握线程的基本操作,如创建线程、线程同步(synchronized关键字、Lock接口)、死锁、线程池等,并理解Java内存模型(JMM)。 6. **IO与NIO**:理解字节流、字符流、缓冲流、对象流的使用,以及...

    Java 学习笔记.zip

    这份"Java学习笔记.zip"文件显然包含了一些关于Java编程的基础到高级的学习资料,特别聚焦于JDK 6版本。JDK(Java Development Kit)是Java开发环境的核心组件,包括了Java编译器、Java运行时环境、以及丰富的API库...

    Java避坑指南:Java高手笔记代码篇.rar

    这份“Java避坑指南:Java高手笔记代码篇”旨在帮助开发者绕过这些潜在的障碍,提升编程效率和代码质量。以下是一些关键的知识点,从标题和描述中可以提炼出来: 1. **异常处理**:Java中的异常处理是程序员必须...

    JAVA学习笔记

    笔记内容包括了几个核心领域,如编程思想、多线程设计模式、网络编程,以及JAVA的新输入/输出(NIO)系统。 首先,编程思想是JAVA学习的基础,它涉及到面向对象编程的概念,如封装、继承、多态,以及如何通过设计...

    Java 疑难杂症_笔记.zip

    笔记可能涵盖了线程安全、死锁、活锁、饥饿等并发问题的解决方案,以及如何正确使用synchronized、volatile、Lock等同步机制。此外,线程池的使用和配置优化也可能是讨论的重点。 第三,异常处理是Java程序稳定性的...

    Java基础尚硅谷宋红康学习笔记

    7. **多线程**:Java内置了对多线程的支持,通过Thread类或实现Runnable接口可以创建并运行多个线程,实现并发执行。 8. **接口与内部类**:接口定义了一组方法签名,提供了一种实现多继承的方式。内部类(包括成员...

    Java 客户端服务器程序 学习笔记

    通过阅读这篇学习笔记,你可以掌握Java客户端服务器编程的基本概念和实践技巧,并能够开发自己的网络应用程序。记住,实践是最好的老师,所以动手尝试创建一个简单的客户端服务器应用程序是巩固理论知识的绝佳方法。

    非常详细javaSE学习笔记.rar

    1. **Java起源与环境搭建**:笔记可能会介绍Java的历史,由Sun Microsystems(现为Oracle Corporation)创建,以及如何安装和配置Java Development Kit (JDK)。 2. **Java语法基础**:包括基本数据类型(如int, ...

    Java进阶笔记.zip

    1. **多线程**:Java提供内置的多线程支持,包括Thread类和Runnable接口,以及并发工具如Semaphore、CyclicBarrier等。学习多线程有助于理解同步和异步操作,以及如何有效地管理资源。 2. **集合框架**:Java集合...

Global site tag (gtag.js) - Google Analytics