为您推荐:
精华内容
最热下载
问答
  • 5星
    15.9MB Yao__Shun__Yu 2021-01-26 09:52:27
  • 5星
    66B weixin_42039715 2021-08-25 18:25:48
  • 5星
    59.25MB q6115759 2021-03-22 13:49:20
  • 5星
    63.04MB qq_41141585 2021-06-17 17:43:19
  • 5星
    44KB qq_52889967 2021-07-07 17:32:35
  • 5星
    165.73MB q6115759 2021-03-11 09:29:13
  • 5星
    8.69MB xiaohua1992 2021-04-12 20:47:00
  • 5星
    2.25MB qq_40866897 2021-10-19 22:45:29
  • 5星
    6KB qq_49101550 2021-02-26 14:18:35
  • 5星
    836KB weixin_44573410 2021-01-22 14:12:43
  • 本身不是为高可用性设计,撑不住高流量容易导致系统崩溃。还有对网络隔离的敏感也导致Zookeeper的脆弱 开启多线程的三种方式 1) 继承thread类 重新run函数 对象。start开启 2) 实现runnnable接口 重写...

    基础部分

    1. 线程和进程的区别

    线程三个基本状态:就绪、执行、阻塞

    线程五个基本操作:创建、就绪、运行、阻塞、终止

    进程四种形式:主从式、会话式、消息或邮箱机制、共享存储区方式

    进程是具有一定功能的程序关于某次数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。一个进程包含多个线程。

    线程是进程的一个实体,是CPU调度和分配的基本单元。

    1. JSP四大域对象和九大内置对象

    四大域对象:PageContext、request、session、servletContext

    九大内置对象:request、response、application、config、Exception、page、out、pageContext、session

    1. 使用final关键词修饰一个变量的时候是引用不能变还是引用的对象不能变?

    Final关键词修饰一个变量是指引用变量不能变。引用变量所指对象的内容是可以变化的。

    1. Private、protected、public的区别

    private:
    继承成员但没有访问权限。(可以通过此类中的protected成员函数和public成员函数访问。)
    protected:
    继承成员,有访问权限,类外没有访问权限,不可将继承的protected修改为private.
    public:
    继承成员,有访问权限,类外有访问权限。

    1. 父类和子类都有静态代码块时,创建子类是先执行哪类?

    静态代码块在JVM加载类的时候先执行,父类先于子类执行。

    1. Junit中before和beforeclass的区别

    Before 在每个测试方法之前都会运行一次,只需要声明public

    BeforeClass 在类中只运行一次,必须声明成public static

    1. 单例模式

       public class Singleton {  
           private static Singleton sl;  
           private Singleton (){}  
           public static synchronized Singleton getInstance() {  
           if (sl== null) {  
               sl= new Singleton();  
           }  
           return sl;  
           }  
       }  
      
    2. Redis数据结构

    String-字符串 Hash-字典 list-列表 set-集合 sorted set-有序集合

    1. HashMap、HashSet和HashTable的区别

    HashMap基于Map接口实现,线程非同步所以不安全。键是唯一不可重复的,但是value值可以重复且允许空值存在。

    HashTable是基于Dictionary类实现,线程默认同步所以是安全的,键值唯一且不为空,value值不能为空值。

    HashSet是基于set实现的,以对象作为元素,且拒绝重复对象。内部使用HashMap实现,其实就是HashMap的一个视图。

    1. ArrayList和LinkedList的区别

    ArrayList是基于动态数组的数据结构,查询较快

    LinkedList是基于链表的数据结构,因为不需要移动数据,所以增删较快。

    1. 线程中wait和sleep的区别

    Wait方法属于Object类,使线程放弃进入执行,进入线程等待池,只能使用notify或notifyAll方法才能唤醒此线程,线程会等待进入线程池。即使在执行此方法时,线程已进入线程池,依然会放弃执行,让出线程池,交出锁。即使线程被激活,也需要等待前方线程执行完毕后才可进入线程池执行。

    Sleep方法属于Thread类,使线程在指定时间内暂停执行,让cup暂时执行其他线程,但这个线程的监控状态依然保持,当执行时间到了以后,该线程恢复到之前状态,继续执行,线程不会释放锁。

    1. Equals和==的区别

    ==是一个运算符,是逻辑上的判断,比较的是引用地址。

    Equals是String的一个方法,是比较引用地址,在Object类时,Equals和==是一样的,对于其他类来说如果重新了Equals方法,则比较的两个对象的数据内容。

    1. HashCode和Equals

    HashCode和Equals都是在Object类中定义的,是对两个对象地址的比较,如果重写了Equals方法就必须重写HashCode方法。

    HashCode方法返回的是对象的散列码,返回值是int类型的散列码;Equals返回的是true和false。

    如果两个对象相同,他们的HashCode值必须相同;如果两个对象的HashCode值相同,他们不一样相同。

    1. 方法重载和重写的区别

    方法重载:在同一个类中,方法名称相同,参数类型和个数不同,返回值也可以不同。

    方法重写:父子类、接口和实现类之间的关系,子类可以重写父类方法,但是参数个数、类型、返回值必须相同。

    1. Junit中before和beforeclass的区别

    Before是初始化方法,在每个程序运行之前都会执行一次。

    Beforeclass在类中只运行一次。

    1. STAR法则

    Situation: 事情是在什么情况下发生

    Task: 你是如何明确你的任务的

    Action: 针对这样的情况分析,你采用了什么行动方式

    Result: 结果怎样,在这样的情况下你学习到了什么

    1. Cookie和Session的区别

    cookie数据存储在客户的浏览器上,cookie是不安全的,别人可以分析存放在本地cookie并进行cookie欺骗;

    Session存储在服务器上,Session是安全的;当访问增多时,Session会占用服务器性能,可以考虑使用cookie

    • 建议将登陆信息等重要信息保存在Session中,其他需要保留的信息可以存在cookie中。
    1. JQuery有哪些选择器

    ID选择器、类选择器、层次选择器、组合选择器、属性选择器、表单选择器等等

    1. 事务的特性和隔离级别

    特性:原子性、一致性、隔离性、持久性。

    隔离级别:
    
     ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
    
     ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
    
     ③ Read committed (读已提交):可避免脏读的发生。
    
     ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
    
    1. POI上传数据量过大

    可分批处理 先行保存部分内容至数据库,再清空list集合,重新导入内容

    1. 前缀编码

    在一个字符集中,任何一个字符的编码都不是另一个字符编码的前缀。

    1. JVM清理垃圾命令

    GC.run

    1. 循环队列引入的目的

    消除线性队列的“假溢出”,充分利用存储空间。

    1. Webservice是什么?它的引擎是什么?

    WebService是一个平台独立的、低耦合的,自包含的、基于可编程的web应用程序,可使用开放的xml标准来描述、发现、发布、协调和配置这些应用程序,是用户开发互操作的分布式系统。最基本的目的就是提供在各个不同平台的不同应用系统的系统工作能力。

    1. Tomcat集群中怎么实现共享

    1:Tomcat的Session复制。在一台Tomcat的Session发生变化时,将变更的数据分发给其它的Tomcat服务器。

    2: 采用 memcached session manager 共享session。

    1. Git和Svn有什么区别?

      1:git是分布式的版本控制系统,SVN不是。GIT和SVN都有自己的集中式版本库或服务器,但是GIT更倾向分布式使用。
      
      2:GIT把内容按数据方式存储,而SVN是按文件存储的。
      
      3:GIT可以很容易的发现未被合并的分支,SVN需要手动运行命令来确定代码是否被合并。
      
      4:GIT没有一个全局的版本号,SVN有。但GIT内容完整性要优于SVN。
      
      5:GIT在下载后即使在不联网状态也可以看到所有数据,但SVN必须要联网。
      
      6:GIT的提交速度优于SVN,且GIT可以有无限个版本库,但SVN只有一个中央数据库,一旦这个中央库有问题,则所有代码都会全部瘫痪。
      
      7:管理一个GIT库相对于管理一个SVN库更容易。
      
    2. dubbo服务开发流程,运行流程?zookeeper注册中心的作用?端口是多少?
      服务容器负责启动,加载,运行服务提供者。

      1. 服务提供者在启动时,向注册中心(默认端口2181)注册自己提供的服务。
      
      2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
      
      3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
      
      4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
      
      5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
      
    3. redis为什么可以做缓存?redis都是怎么用的?都用来存什么了?redis的存储结构?Redis集群搭建?redis的事务;redis丢失问题

    • 使用redis做缓存的原因:

        redis是用C语言编写的,稳定性和性能更好。支持集群模式和持久化等特性,不会应为缓存量太多而导致虚拟机崩溃。Redis是独立部署的,即使网站更新,redis缓存的数据也不会消失。
        
        集群搭建(redis需要3台主机,3台从机,则配置6台,需要6个端口):
      
        1:安装ruby环境,上传接口工程,安装接口程序,拷贝脚本到指定位置
        
        2:创建6个redis实例,修改配置文件 ,然后启动所有redis实例(为简化启动步骤,可编写启动脚本)。
        
        3:执行创建集群的命令,连接测试
      

    redis的事务

    Redis的事务是一组命令的集合,Redis事务的实现需要用到 MULTI 和 EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。

    redis丢失问题常见原因:

    . 程序bug或人为误操作
    · 因客户端缓冲区内存使用过大,导致大量键被LRU淘汰
    · 主库故障后自动重启,可能导致数据丢失
    · 网络分区的问题,可能导致短时间的写入数据丢失
    · 主从复制数据不一致,发生故障切换后,出现数据丢失
    · 大量过期键,同时被淘汰清理
    
    1. 消息中间件acitveMQ的作用、原理?

    作用:acitveMQ就是消息队列,activemq安装之后,会有一个broker(经纪人)。

    消息的生产者将消息发送到broker中,它不关心谁消费该消息。

    消息的消费者去broker中获取信息,它不关心谁提供消息

    1. AJAX的怎样实现同步或者怎样实现异步?

      	$.ajax({
      	    async:false // 为false 时 为同步, 默认 为true , 为异步
      	})
      
    2. fastDFS分布式文件系统

    fastDFS有两个角色:跟踪器(tracker)和存储节点(storage);

    • 存储数据:

    跟踪器负责记录图片地址,和响应java接口访问。java接口要想储存图片地址需向跟踪器发送请求,然后由跟踪器查找图片仓库地址发给java接口,同时记录储存过程,

    Java接口配IP是配2个的,因为有2个跟踪器,而java接口连接IP时并不是智能的,如果连接第一个跟踪器没反应(第一个没反应不是忙就是挂了),它就会连接第二个跟踪器,不管连哪个跟踪器,最终都会返回一个地址给java接口。而两个跟踪器之间是有通信的,它们会把信息同步的,这个信息也就是meta信息,也就是管理的帐本。

    跟踪器和存储节点有通信间隔时间,这个时间由我们决定。而存储节点之间也是有通信的,如果有一天存储节点和存储节点的仓库都满了,就扩张仓库,创建下一组存储节点和存储仓库。

    • 取数据:

        取数据的时候可以用java接口取,也可以用页面里的<img src=”http//…..jpg/>”取,但是src属性会在页面加载后发出2次请求。Src会根据地址去找跟踪器,而跟踪器会告诉它这地址图片在哪个存储节点身上,跟踪器这台机器上搭建是nginx服务器(反向代理服务器)这个服务器是用来解决高并发用的。Nginx服务器会根据你的路径找到存储节点身上的图片。然后再将存储节点的图片拿回来,再加载给src,到img标签里。
      
    • 启动:

        先设置IP再修改IP,然后三个命令分别启动跟踪器,存储节点,Nginx服务器
      
    1. Maven-热部署

      热部署:就是maven管理的项目发布到测试服务器,省去以往发布时要不停的启动、关闭tomcat这些繁琐	的过程;热:就是tomcat一直保持开启状态,
      
      1、设置tomcat用户名和密码,然后启动tomcat
      
      2、在你所要发布的项目里的pom.xml里设置你要发布项目的路径同时把tomcat用户名和密码也设置上
      
      3、发送发布命tomcat7:deploy
      
      4、强硬发布命令:tomcat7:redeploy
      
    2. Log4j的输出级别都有哪些

      DEBUG Level: 指出细粒度信息事件对调试应用程序是非常有帮助的,就是输出debug的信息.
      INFO level: 表明消息在粗粒度级别上突出强调应用程序的运行过程,就是输出提示信息.
      WARN level: 表明会出现潜在错误的情形,就是显示警告信息.
      ERROR level: 指出虽然发生错误事件,但仍然不影响系统的继续运行.就是显示错误信息.
      FATAL level: 指出每个严重的错误事件将会导致应用程序的退出.
      ALL level: 是最低等级的,用于打开所有日志记录.
      OFF level: 是最高等级的,用于关闭所有日志记录.
      
    3. zookeeper存在什么缺陷

      本身不是为高可用性设计,撑不住高流量容易导致系统崩溃。还有对网络隔离的敏感也导致Zookeeper的脆弱
      
    4. 开启多线程的三种方式

      1) 继承thread类  重新run函数  对象。start开启
      
      2) 实现runnnable接口  重写run函数
      
      3) 实现callable
      
    5. 接口collection和抽象类abstrator class 的区别

      1)接口是公开的,不能有私有方法和变量,但是抽象类可以
      
      2)实现一个接口必须实现接口的方法,抽象类可以重写也可以不重写
      
      3)接口可以实现多重继承,抽象类只能实现多个接口
      
    6. override和overload的区别

      重写是指子类继承父类,重写父类的方法。重载是多态的一种表现形式,是指在同一类中方法名相同参数列表不同的同命名方法。
      
    7. 匿名内部类

      匿名内部类也就是没有名字的内部类
      
      正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
      
      但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
      

    框架部分

    1. SpringMVC接收参数的方式

       1:通过@PathVariable获取路径中传递的参数	在方法参数前
       
       2:通过@ModelAttribute获取post请求中的form表单数据	在方法参数前
       
       3:通过HttpServletRequest获取
       
       4:用@RequestParam
      
    2. SpringMVC配置文件

       Web.xml:初始化spring容器	加载配置文件	contextConfigLocation
       
       配置前端控制器	加载SpringMVC.Xml	设定startup为1,启动时加载 过滤所有请求
       
       统一编码方式	CharacterEncodingFilter	过滤所有请求
       
       Spring.xml:配置包扫描器	context:component-scan
       
       配置注解驱动	mvc:annotation-driven
       
       配置视图解析器	InternalResourceViewResolver <bean>
       
       加载静态资源	mvc:resources
       
       配置多部件解析器	CommonsMultipartResolver	设定默认编码和文件上传的最大值
       
       加载Java的其余配置文件	context:property-placeholder
      
    3. ssm和ssh的区别或者优势

       SSH通常指Struts2做控制器,Spring管理各种组件,Hibernate负责持久化层。
       
       SSM通常指SpringMVC做控制器,Spring管理各层组件,Mybatis负责持久化层。
      

    相同点:

    1:Spring依赖注入来管理各层组件

    2:使用面向切面的AOP编程思想管理事务、日志、权限等。

    不同点:

    Struts2和SpringMVC控制器控制视图和交互机制不同。

    1. Struts2和SpringMVC的区别

       1:SpringMVC开发效率高于Struts2,且SpringMVC以基本实现0配置。
       
       2:SpringMVC实现依赖Servlet,是单例的,参数基于方法进行封装。
       
       3:SpringMVC是方法级别的拦截,一个方法对应一个request上下文,方法对应URL。方法之间的变量是不共享的,方法是独立的,可以使用注解方式接收参数。
       
       4:Struts2是类级别的拦截,一个类对应一个request的上下文,配置文件较复杂,架构比较费时费力。虽然每个方法之间也是独立的,但所有类变量都是共享的,虽然不影响运行,但是编码、读程序却比较麻烦。
       
       5:Struts2实现依赖过滤器,是多例的,参数是基于属性进行封装。
       
       6:Struts2需要封装每一个Request,把每个生命周期变量封装成一个个的MAP集合,并要保证线程的安全,比较耗费内存。
      
    2. Hibernate和MYbatis的区别

    相同点:

    Hibernate和Mybatis都是通过SessionFactoryBuider由xml文件生成SessionFactory,然后生成Session,由Session开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。都支持JDBC和JTA事务处理。

    不同点:

    Mybatis:Mybatis可以进行更为细致的SQL优化,可以减少查询字段。

    Mybatis相对于Hibernate更容易掌握,门栏较低。

    Hibernate:Hibernate的DAO层开发比Mybatis更简单,因为Mybatis需要维 护SQL和映射结果。

    Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。

    Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。

    Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

    1. Hibernate的一级缓存和二级缓存

       Hibernate的一级缓存指的是Session缓存,因为Session缓存是内置的,是Hibernate的默认配置;二级缓存指的是SessionFactory的外置缓存,因为外置缓存是数据库数据的拷贝,介质可以是内存或硬盘,需要手动开启。
      
    2. spring的事务管理

       Spring的事务管理分为声明式和编程式。声明式事务可以使用tx标签方式、使用代理方式以及拦截器方式。编程式事务需要在配置中配置Session工厂,配置事务管理器,开启注解扫描,使用@Service
      
    3. springmvc的注解都有哪些

       @Controller  @requestMapping	@PathVariable	@RequestParam@RequestBody	@ResponseBody	@RestController @ModelAttribute
      
    4. hibernate的优化

       1:数据库设计时要降低关联的复杂性,尽量不使用联合主键,适用冗余数据,不过分追求高范式
      
       2:使用延迟加载
      
    5. hibernate的五个核心类

    Configuration,sessionfactory,Session,query接口,transaction接口

    1. Spring的优点: 缺点
      优点:

      方便解耦,简化开发---Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
      
      AOP编程的支持---Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
      
      声明式事务的支持---只需要通过配置就可以完成对事务的管理,而无需手动编程
      
      方便程序的测试---Spring对Junit4支持,可以通过注解方便的测试Spring程序
      
      方便集成各种优秀框架---Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
      
      降低JavaEE API的使用难度---Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
      

    缺点:

    	jsp中要写很多代码、控制器过于灵活,缺少一个公用控制器
    
    1. spring工作机制和为什么要用

      工作机制:Spring的核心就是IOC和AOP所以Spring的工作机制简单的理解也就是IOC和AOP的工作机制。
      

    原因:借助于Spring AOP,Spring IOC能够很方便的使用到非常健壮、灵活的企业级服务,通过使用IoC能够降低组件之间的耦合度,最终,能够提高类的重用性,利于测试,而且更利于整个产品或系统集成和配置

    1. AOP和IOC概念和在spring中如何应用

    Springmvc是spring一部分

    IOC:控制反转,生产对象用。控制权由应用代码中转到了外部容器,控制权的转移,是所谓的反转。

    AOP:面向切面编程,底层使用动态代理,作用:管理事务和安全监控,事务 只需要配置一次就不用再配置。

    1. MVC设计思想
    • Mvc是一个架构设计思想:

        用户发送请求至控制器(Controller),控制层把用户请求转发给模型Model层进行数据处理,Model层内包含javabean组件、领域模型、业务层、持久层,Model层处理完数据层响应给控制层,控制层再次把数据发送给视图View进行视图编译,然后由View层把视图页面返回给控制层,控制层再响应给用户。
      
    1. Springmvc框架原理

    2. 用户发送请求给前端控制器DisPatcherserlvlet:前端控制器只负责接受请求,转发请求,响应结果数据。DispatcherServlet就是一个中央控制器。
      前端控制器需要委托处理器映射器去寻找获取Handler(Controller)
      处理器映射器根据浏览器请求去寻找指定属性的Controller
      返回执行Chain(链),链中具有很多拦截器 ,Handler(Controller)在拦截器中间被返回给前端控制器。
      前端控制器拿到Controller以后需要去执行Controller,交给处理器适配器去执行
      处理器适配器负责调用Controller里面的方法,进行执行Controller
      Controller返回一个模型视图(ModelAndView)
      处理器适配器把这个ModelandVIew交给前端控制器
      前端控制器把模型视图ModelAndView给视图解析器(viewResolver)解析出物理视图
      返回给前端控制器
      
      渲染视图:el+jsp el表达把model数据解析封装到jsp页面的过程就叫渲染视图
      返回用户
      
    3. POJO概念

      POJO是mybatis中的返回值的参数类型,它和bean一样意思。Bean是指类,而POJO把类看成对象。Mybatis是在JDBC上做的封装,为了使SQL语句不再是硬编码和不用再按顺序执行,为了在框架里获取sql语句而设定的一种概念,得到的是动态SQL。
      
    4. Freemaker页面静态化怎么实现的,商品下架怎么删除,静态化页面可以发送异步请求吗?

    • Freemaker放在那里,如何访问
      实现过程:

        在商品添加服务中发送商品ID消息,接收消息中的商品ID。
        
        从spring上下文中获取Freemarker的配置文件(configuration)对象。
        
        通过configuration创建模板(template对象),模板的名称在java配置文件中配置。
        
        创建模板数据:根据商品ID查询出商品信息,如果没有数据,抛出异常。
        
        指定输出文本。文本的路径在java配置文件中配置,文本的名称是商品ID,文本的后缀在java配置文件中配置。
        
        调用template的process方法,生成输出文件。
        
        可以发送异步请求,使用Nginx访问
      
    1. Hibernate对象的三种形态

    临时状态(transient):刚用new语句创建,还没有被持久化,不处于Session的缓存中。处于临时状态的Java对象称为临时对象。

    持久化状态(persistent):已经被持久化,加入到Session的缓存中。处于持久化状态的Java对象称为持久化对象。

    游离状态(detached):已经被持久化,但不再处于Session的缓存中。处于游离状态的Java对象称为游离对象。

    Java对象:开始生命周期——》临时状态——》持久化状态——》游离状态——》结束生命周期

    1. servlet的生命周期

    1、实例化阶段 调用init()方法

    2、服务阶段  调用service()方法

    3、销毁阶段  调用destroy()方法

    	首先客户发送一个请求,Servlet是调用service()方法对请求进行响应,通过源代码可见,service()方法中对请求的方式进行了匹配,选择调用doGet,doPost等这些方法,然后再进入对应的方法中调用逻辑层的方法,实现对客户的响应。在Servlet接口和GenericServlet中是没有doGet,doPost等等这些方法的,HttpServlet中定义了方法,但是都是返回error信息,所以,我们每次定义一个Servlet的时候,都必须实现doPost,doGet等这些方法。
    
    1. ORM

      对象关系映射,也就是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 。从效果上说,它其实是创建了一个可在编程语言里使用的--“虚拟对象数据库”。
      
    2. JVM

    3. JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的字节码程序。java编译器只需面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译器,编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。
      

    JVM执行程序的过程 :

    I.加载.class文件

    II.管理并分配内存

    III.执行垃圾收集

    1. JDBC

      JDBC(java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,同时,JDBC也是个商标名。
      
    2. Struts2框架工作流程及原理

      1、客户端浏览器发出HTTP请求.
      
      2、根据web.xml配置,该请求被FilterDispatcher接收
      
      3、根据struts.xml配置,找到需要调用的Action类和方法, 并通过IoC方式,将值注入给Aciton
      
      4、Action调用业务逻辑组件处理业务逻辑,这一步包含表单验证。
      
      5、Action执行完毕,根据struts.xml中的配置找到对应的返回结果result,并跳转到相应页面
      
      6、返回HTTP响应到客户端浏览器
      

    原理:

    	1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 
    	2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin) 
    	3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action 
    	4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy 
    	5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类 
    	6 ActionProxy创建一个ActionInvocation的实例。 
    	7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。 
    	8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper 
    

    数据库部分

    1. 数据库优化问题

       1:表的设计要符合三范式。
       
       2:添加适当存储过程,触发器,事务等。
       
       3:添加适当的索引,索引对查询速度影响很大,必须添加索引。主键索引,唯一索引,普通索引,全文索引
       
       4:读写分离(主从数据库,主数据库进行写的操作,从数据库惊醒读的操作,主数据库将数据更新到从数据库)
      
       5:对sql语句的一些优化,(查询执行速度比较慢的sql语句)
       
       a:查询中避免使用通配符,尽量使用索引。选择联合查询的联合次序
       
       b:在子查询中避免使用in 或 not in 语句,使用where (NOT) exists的效果要好的多;避免使用BY RAND随机显示结果。
       
       c:使用联合(UNION)代替手动创建的临时表,拆分表格。
       
       d:尽可能的使用NOT NULL(非空),对MySQL的配置进行优化
      
       6:分表分区
      
       分表:把一张大表分成多张表。分区:把一张表里面的分配到不同的区域存储,对mysql服务器硬件的升级操作。
      
    2. 如果数据库里边的大表添加字段 怎么弄效率最高

    alter table ~ add ~ 添加列

    1. mysql默认的最大连接数是多少?

       mysql的最大连接数默认是100, 最大可以达到16384
      
    2. mysql分页;limit关键字

       limit关键字:LIMIT 可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)
      
    3. 创建索引库的优缺点?

    优点:通过创建唯一性索引,可以保证数据库中每一行数据的唯一性,2,可以大大加快数据的检索速度,这也是创建索引的最主要的原因,3.可以加速表与表之间的连接,特别是在实现数据的参考完整性。

    缺点:创建索引和维护索引需要消耗时间,这种时间随着数据的增加而增加,2.索引占用物理空间,需要的空间变大,3.当对数据库中的数据进行增删改的时候,索引也需要动态的维护,此时降低了维护速度。

    1. 集合去重,数据库去重;(集合去重有contains方法;数据库去重用group by)
    • 集合去重:

        a:转化为Set集合,因为HashSet集合不允许重复值存在。
        
        b:使用双重循环删除重复的值或者用null代替
        
        c:用contains方法
      
    • 数据库去重:

        a:使用嵌套的查询 得到所有的不重复数据的Id,使用 not in 关键字删除所有ID不在以上范围中的数据。
        
        b:使用嵌套的查询 得到所有的不重复数据的Id,将所有数据存储到一个临时表中,删除原表,重新构建原表,将临时表数据导入原表,删除临时表
      
    1. 怎样建立索引?
    • 普通索引:添加index

    Alter table user add index_name(name),括号内为字段名称

    • 主键索引

    Alert table user add primary key(id)

    • 唯一索引:添加unique

    Alert table user add unique (creattime)

    • 全文索引:添加fulltext

    Alert table user add fulltext(name)

    1. mysql存储过程

       Mysql存储过程就是为完成特定功能的SQL语句集,经过编译之后存储在数据库中,当需要使用该组SQL语句时,用户只需要通过指定存储过程的名字并给定参数就可以调用。
      
       存储过程是一个可编程的函数,在数据库中创建并保存。可以有SQL语句和一些特殊的控制结构组成。可以看做是对编程中面向对象的模拟。
      
    2. MySQL与Oracle的区别
      1. Oracle是大型数据库而Mysql是中小型数据库,Oracle市场占有率达40%,Mysql只有20%左右,同时Mysql是开源免费的而Oracle价格非常高。

       2. Oracle支持大并发,大访问量,是OLTP最好的工具。
       
       3. 安装所用的空间差别也是很大的,Mysql安装完后才152M而Oracle有3G左右,且使用的时候Oracle占用特别大的内存空间和其他机器性能。
      
       4.Oracle也Mysql操作上的一些区别
      
       ①主键 Mysql一般使用自动增长类型,在创建表时只要指定表的主键为auto increment,插入记录时,不需要再指定该记录的主键值,Mysql将自动增长;Oracle没有自动增长类型,主键一般使用的序列,插入记录时将序列号的下一个值付给该字段即可;只是ORM框架是只要是native主键生成策略即可。
       
       ②单引号的处理 MYSQL里可以用双引号包起字符串,ORACLE里只可以用单引号包起字符串。在插入和修改字符串前必须做单引号的替换:把所有出现的一个单引号替换成两个单引号。
       
       ③翻页的SQL语句的处理 MYSQL处理翻页的SQL语句比较简单,用LIMIT 开始位置, 记录个数;ORACLE处理翻页的SQL语句就比较繁琐了。每个结果集只有一个ROWNUM字段标明它的位置, 并且只能用ROWNUM<100, 不能用ROWNUM>80
       
       ④ 长字符串的处理 长字符串的处理ORACLE也有它特殊的地方。INSERT和UPDATE时最大可操作的字符串长度小于等于4000个单字节, 如果要插入更长的字符串, 请考虑字段用CLOB类型,方法借用ORACLE里自带的DBMS_LOB程序包。插入修改记录前一定要做进行非空和长度判断,不能为空的字段值和超出长度字段值都应该提出警告,返回上次操作。 ⑤空字符的处理 MYSQL的非空字段也有空的内容,ORACLE里定义了非空字段就不容许有空的内容。按MYSQL的NOT NULL来定义ORACLE表结构, 导数据的时候会产生错误。因此导数据时要对空字符进行判断,如果为NULL或空字符,需要把它改成一个空格的字符串。
       
       ⑥字符串的模糊比较 MYSQL里用 字段名 like '%字符串%',ORACLE里也可以用 字段名 like '%字符串%' 但这种方法不能使用索引, 速度不快。
       
       ⑦Oracle实现了ANSII SQL中大部分功能,如,事务的隔离级别、传播特性等而Mysql在这方面还是比较的弱
      

    转载至:https://www.cnblogs.com/779084229yyt/p/8405352.html 仅为收藏,如有侵权,请联系本博主

    展开全文
    w1403575609 2018-11-05 15:42:22
  • 该缓冲有助于控制和优化数据流经过系统的速度。 9. 理解数据流 在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象,是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定...

    消息中间件之间可以细度:   http://www.cnblogs.com/charlesblc/p/6058799.html

    消息队列-推/拉模式学习 & ActiveMQ及JMS学习:https://www.cnblogs.com/charlesblc/p/6045238.html

    消息队列之观察者模式可参考:https://www.cnblogs.com/taotingkai/p/6645436.html

    消息队列使用的四大场景
    http://blog.csdn.net/cws1214/article/details/52922267

    如果是使用的linux下单间连接activeMq的时候记得关闭防火墙测试

    原因:防火墙未关闭,必须关闭防火墙,设置端口都不好使,必须关闭。
    解决办法:关闭防火墙,一切ok!

    下面说一下我们为什么要使用消息中间件有哪些优点和好处:

    1. 解耦
    在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
    2. 冗余
    有时在处理数据的时候处理过程会失败。除非数据被持久化,否则将永远丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。在被许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理过程明确的指出该消息已经被处理完毕,确保你的数据被安全的保存直到你使用完毕。
    3. 扩展性
    因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的;只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。
    4. 灵活性 & 峰值处理能力
    当你的应用上了Hacker News的首页,你将发现访问流量攀升到一个不同寻常的水平。在访问量剧增的情况下,你的应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为 以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住增长的访问压力,而不是因为超出负荷的请求而完全崩溃。 请查看我们关于峰值处理能力的博客文章了解更多此方面的信息。
    5. 可恢复性
    当体系的一部分组件失效,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。而这种允许重试或者延后处理请求的能力通常是造就一个略感不便的用户和一个沮丧透顶的用户之间的区别。
    6. 送达保证
    消息队列提供的冗余机制保证了消息能被实际的处理,只要一个进程读取了该队列即可。在此基础上,IronMQ提供了一个"只送达一次"保证。无论有多少进 程在从队列中领取数据,每一个消息只能被处理一次。这之所以成为可能,是因为获取一个消息只是"预定"了这个消息,暂时把它移出了队列。除非客户端明确的 表示已经处理完了这个消息,否则这个消息会被放回队列中去,在一段可配置的时间之后可再次被处理。
    7.排序保证
    在许多情况下,数据处理的顺序都很重要。消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。IronMO保证消息浆糊通过FIFO(先进先出)的顺序来处理,因此消息在队列中的位置就是从队列中检索他们的位置。
    8.缓冲
    在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行--写入队列的处理会尽可能的快速,而不受从队列读的预备处理的约束。该缓冲有助于控制和优化数据流经过系统的速度。
    9. 理解数据流
    在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象,是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定那些表现不佳的处理过程或领域,这些地方的数据流都不够优化。
    10. 异步通信
    很多时候,你不想也不需要立即处理消息。消息队列提供了异步处理机制,允许你把一个消息放入队列,但并不立即处理它。你想向队列中放入多少消息就放多少,然后在你乐意的时候再去处理它们。

      ActiveMQ官网下载地址:http://activemq.apache.org/download.html

      ActiveMQ 提供了Windows 和Linux、Unix 等几个版本,楼主这里选择了Linux 版本下进行开发。

     

     

      下载完安装包,解压之后的目录:

     

       从它的目录来说,还是很简单的: 

      • bin存放的是脚本文件
      • conf存放的是基本配置文件
      • data存放的是日志文件
      • docs存放的是说明文档
      • examples存放的是简单的实例
      • lib存放的是activemq所需jar包
      • webapps用于存放项目的目录

     

    2、启动ActiveMQ 


       进入到ActiveMQ 安装目录的Bin 目录,linux 下输入 ./activemq start 启动activeMQ 服务。

       输入命令之后,会提示我们创建了一个进程IP 号,这时候说明服务已经成功启动了。

      

      ActiveMQ默认启动时,启动了内置的jetty服务器,提供一个用于监控ActiveMQ的admin应用。 
      admin:http://127.0.0.1:8161/admin/

     

      我们在浏览器打开链接之后输入账号密码(这里和tomcat 服务器类似)

      默认账号:admin

      密码:admin

      

       到这里为止,ActiveMQ 服务端就启动完毕了。

       ActiveMQ 在linux 下的终止命令是 ./activemq stop

     

    3、创建一个ActiveMQ工程


     

       项目目录结构:

      

      上述在官网下载ActiveMq 的时候,我们可以在目录下看到一个jar包:

      

      这个jar 包就是我们需要在项目中进行开发中使用到的相关依赖。

     

      3.1 创建生产者

    复制代码
    public class Producter {
    
        //ActiveMq 的默认用户名
        private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
        //ActiveMq 的默认登录密码
        private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
        //ActiveMQ 的链接地址
        private static final String BROKEN_URL = ActiveMQConnection.DEFAULT_BROKER_URL;
    
        AtomicInteger count = new AtomicInteger(0);
        //链接工厂
        ConnectionFactory connectionFactory;
        //链接对象
        Connection connection;
        //事务管理
        Session session;
        ThreadLocal<MessageProducer> threadLocal = new ThreadLocal<>();
    
        public void init(){
            try {
                //创建一个链接工厂
                connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEN_URL);
                //从工厂中创建一个链接
                connection  = connectionFactory.createConnection();
                //开启链接
                connection.start();
                //创建一个事务(这里通过参数可以设置事务的级别)
                session = connection.createSession(true,Session.SESSION_TRANSACTED);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
        public void sendMessage(String disname){
            try {
                //创建一个消息队列
                Queue queue = session.createQueue(disname);
                //消息生产者
                MessageProducer messageProducer = null;
                if(threadLocal.get()!=null){
                    messageProducer = threadLocal.get();
                }else{
                    messageProducer = session.createProducer(queue);
                    threadLocal.set(messageProducer);
                }
               while(true){
                    Thread.sleep(1000);
                    int num = count.getAndIncrement();
                    //创建一条消息
                    TextMessage msg = session.createTextMessage(Thread.currentThread().getName()+
                            "productor:我是大帅哥,我现在正在生产东西!,count:"+num);
                    System.out.println(Thread.currentThread().getName()+
                            "productor:我是大帅哥,我现在正在生产东西!,count:"+num);
                    //发送消息
                    messageProducer.send(msg);
                    //提交事务
                    session.commit();
                }
            } catch (JMSException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

         

      3.2 创建消费者

    复制代码
    public class Comsumer {
    
        private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
    
        private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
    
        private static final String BROKEN_URL = ActiveMQConnection.DEFAULT_BROKER_URL;
    
        ConnectionFactory connectionFactory;
    
        Connection connection;
    
        Session session;
    
        ThreadLocal<MessageConsumer> threadLocal = new ThreadLocal<>();
        AtomicInteger count = new AtomicInteger();
    
        public void init(){
            try {
                connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEN_URL);
                connection  = connectionFactory.createConnection();
                connection.start();
                session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
    
        public void getMessage(String disname){
            try {
                Queue queue = session.createQueue(disname);
                MessageConsumer consumer = null;
    
                if(threadLocal.get()!=null){
                    consumer = threadLocal.get();
                }else{
                    consumer = session.createConsumer(queue);
                    threadLocal.set(consumer);
                }
                while(true){
                    Thread.sleep(1000);
                    TextMessage msg = (TextMessage) consumer.receive();
                    if(msg!=null) {
                        msg.acknowledge();
                        System.out.println(Thread.currentThread().getName()+": Consumer:我是消费者,我正在消费Msg"+msg.getText()+"--->"+count.getAndIncrement());
                    }else {
                        break;
                    }
                }
            } catch (JMSException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

     

     

    4、运行ActiveMQ项目


     

      4.1 生产者开始生产消息

    复制代码
    public class TestMq {
        public static void main(String[] args){
            Producter producter = new Producter();
            producter.init();
            TestMq testMq = new TestMq();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Thread 1
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 2
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 3
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 4
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 5
            new Thread(testMq.new ProductorMq(producter)).start();
        }
    
        private class ProductorMq implements Runnable{
            Producter producter;
            public ProductorMq(Producter producter){
                this.producter = producter;
            }
    
            @Override
            public void run() {
                while(true){
                    try {
                        producter.sendMessage("Jaycekon-MQ");
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    复制代码

       运行结果:

    复制代码
     INFO | Successfully connected to tcp://localhost:61616
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:0
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:1
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:3
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:2
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:4
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:5
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:6
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:7
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:8
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:9
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:10
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:11
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:12
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:13
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:14
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:15
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:16
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:17
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:18
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:19
    复制代码

      

     

      4.2 消费者开始消费消息

    复制代码
    public class TestConsumer {
        public static void main(String[] args){
            Comsumer comsumer = new Comsumer();
            comsumer.init();
            TestConsumer testConsumer = new TestConsumer();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
        }
    
        private class ConsumerMq implements Runnable{
            Comsumer comsumer;
            public ConsumerMq(Comsumer comsumer){
                this.comsumer = comsumer;
            }
    
            @Override
            public void run() {
                while(true){
                    try {
                        comsumer.getMessage("Jaycekon-MQ");
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    复制代码

      运行结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    INFO | Successfully connected to tcp: //localhost:61616
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:4--->0
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-4productor:我是大帅哥,我现在正在生产东西!,count:36--->1
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:38--->2
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:37--->3
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:2--->4
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:40--->5
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:42--->6
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-4productor:我是大帅哥,我现在正在生产东西!,count:41--->7
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:1--->8
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:44--->9
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-4productor:我是大帅哥,我现在正在生产东西!,count:46--->10
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:45--->11
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:3--->12
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:48--->13
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:50--->14
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:49--->15
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:54--->16
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:6--->17
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:52--->18
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:53--->19
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:58--->20

      

      查看运行结果,我们可以做ActiveMQ 服务端:http://127.0.0.1:8161/admin/ 里面的Queues 中查看我们生产的消息。

     

     

    5、ActiveMQ的特性


     5.1 ActiveMq 的特性 

    1. 多种语言和协议编写客户端。语言: Java, C, C++, C#, Ruby, Perl, Python, PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
    2. 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
    3. 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
    4. 通过了常见J2EE服务器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
    5. 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
    6. 支持通过JDBC和journal提供高速的消息持久化
    7. 从设计上保证了高性能的集群,客户端-服务器,点对点
    8. 支持Ajax
    9. 支持与Axis的整合
    10. 可以很容易得调用内嵌JMS provider,进行测试

     

     5.2 什么情况下使用ActiveMQ?

    1. 多个项目之间集成 
      (1) 跨平台 
      (2) 多语言 
      (3) 多项目
    2. 降低系统间模块的耦合度,解耦 
      (1) 软件扩展性
    3. 系统前后端隔离 
      (1) 前后端隔离,屏蔽高安全区

      ActiveMQ官网下载地址:http://activemq.apache.org/download.html

      ActiveMQ 提供了Windows 和Linux、Unix 等几个版本,楼主这里选择了Linux 版本下进行开发。

     

     

      下载完安装包,解压之后的目录:

     

       从它的目录来说,还是很简单的: 

      • bin存放的是脚本文件
      • conf存放的是基本配置文件
      • data存放的是日志文件
      • docs存放的是说明文档
      • examples存放的是简单的实例
      • lib存放的是activemq所需jar包
      • webapps用于存放项目的目录

     

    2、启动ActiveMQ 


       进入到ActiveMQ 安装目录的Bin 目录,linux 下输入 ./activemq start 启动activeMQ 服务。

       输入命令之后,会提示我们创建了一个进程IP 号,这时候说明服务已经成功启动了。

      

      ActiveMQ默认启动时,启动了内置的jetty服务器,提供一个用于监控ActiveMQ的admin应用。 
      admin:http://127.0.0.1:8161/admin/

     

      我们在浏览器打开链接之后输入账号密码(这里和tomcat 服务器类似)

      默认账号:admin

      密码:admin

      

       到这里为止,ActiveMQ 服务端就启动完毕了。

       ActiveMQ 在linux 下的终止命令是 ./activemq stop

     

    3、创建一个ActiveMQ工程


     

       项目目录结构:

      

      上述在官网下载ActiveMq 的时候,我们可以在目录下看到一个jar包:

      

      这个jar 包就是我们需要在项目中进行开发中使用到的相关依赖。

     

      3.1 创建生产者

    复制代码
    public class Producter {
    
        //ActiveMq 的默认用户名
        private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
        //ActiveMq 的默认登录密码
        private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
        //ActiveMQ 的链接地址
        private static final String BROKEN_URL = ActiveMQConnection.DEFAULT_BROKER_URL;
    
        AtomicInteger count = new AtomicInteger(0);
        //链接工厂
        ConnectionFactory connectionFactory;
        //链接对象
        Connection connection;
        //事务管理
        Session session;
        ThreadLocal<MessageProducer> threadLocal = new ThreadLocal<>();
    
        public void init(){
            try {
                //创建一个链接工厂
                connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEN_URL);
                //从工厂中创建一个链接
                connection  = connectionFactory.createConnection();
                //开启链接
                connection.start();
                //创建一个事务(这里通过参数可以设置事务的级别)
                session = connection.createSession(true,Session.SESSION_TRANSACTED);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
        public void sendMessage(String disname){
            try {
                //创建一个消息队列
                Queue queue = session.createQueue(disname);
                //消息生产者
                MessageProducer messageProducer = null;
                if(threadLocal.get()!=null){
                    messageProducer = threadLocal.get();
                }else{
                    messageProducer = session.createProducer(queue);
                    threadLocal.set(messageProducer);
                }
               while(true){
                    Thread.sleep(1000);
                    int num = count.getAndIncrement();
                    //创建一条消息
                    TextMessage msg = session.createTextMessage(Thread.currentThread().getName()+
                            "productor:我是大帅哥,我现在正在生产东西!,count:"+num);
                    System.out.println(Thread.currentThread().getName()+
                            "productor:我是大帅哥,我现在正在生产东西!,count:"+num);
                    //发送消息
                    messageProducer.send(msg);
                    //提交事务
                    session.commit();
                }
            } catch (JMSException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

         

      3.2 创建消费者

    复制代码
    public class Comsumer {
    
        private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
    
        private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
    
        private static final String BROKEN_URL = ActiveMQConnection.DEFAULT_BROKER_URL;
    
        ConnectionFactory connectionFactory;
    
        Connection connection;
    
        Session session;
    
        ThreadLocal<MessageConsumer> threadLocal = new ThreadLocal<>();
        AtomicInteger count = new AtomicInteger();
    
        public void init(){
            try {
                connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEN_URL);
                connection  = connectionFactory.createConnection();
                connection.start();
                session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
    
        public void getMessage(String disname){
            try {
                Queue queue = session.createQueue(disname);
                MessageConsumer consumer = null;
    
                if(threadLocal.get()!=null){
                    consumer = threadLocal.get();
                }else{
                    consumer = session.createConsumer(queue);
                    threadLocal.set(consumer);
                }
                while(true){
                    Thread.sleep(1000);
                    TextMessage msg = (TextMessage) consumer.receive();
                    if(msg!=null) {
                        msg.acknowledge();
                        System.out.println(Thread.currentThread().getName()+": Consumer:我是消费者,我正在消费Msg"+msg.getText()+"--->"+count.getAndIncrement());
                    }else {
                        break;
                    }
                }
            } catch (JMSException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

     

     

    4、运行ActiveMQ项目


     

      4.1 生产者开始生产消息

    复制代码
    public class TestMq {
        public static void main(String[] args){
            Producter producter = new Producter();
            producter.init();
            TestMq testMq = new TestMq();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Thread 1
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 2
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 3
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 4
            new Thread(testMq.new ProductorMq(producter)).start();
            //Thread 5
            new Thread(testMq.new ProductorMq(producter)).start();
        }
    
        private class ProductorMq implements Runnable{
            Producter producter;
            public ProductorMq(Producter producter){
                this.producter = producter;
            }
    
            @Override
            public void run() {
                while(true){
                    try {
                        producter.sendMessage("Jaycekon-MQ");
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    复制代码

       运行结果:

    复制代码
     INFO | Successfully connected to tcp://localhost:61616
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:0
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:1
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:3
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:2
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:4
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:5
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:6
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:7
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:8
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:9
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:10
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:11
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:12
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:13
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:14
    Thread-6productor:我是大帅哥,我现在正在生产东西!,count:15
    Thread-3productor:我是大帅哥,我现在正在生产东西!,count:16
    Thread-5productor:我是大帅哥,我现在正在生产东西!,count:17
    Thread-2productor:我是大帅哥,我现在正在生产东西!,count:18
    Thread-4productor:我是大帅哥,我现在正在生产东西!,count:19
    复制代码

      

     

      4.2 消费者开始消费消息

    复制代码
    public class TestConsumer {
        public static void main(String[] args){
            Comsumer comsumer = new Comsumer();
            comsumer.init();
            TestConsumer testConsumer = new TestConsumer();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
            new Thread(testConsumer.new ConsumerMq(comsumer)).start();
        }
    
        private class ConsumerMq implements Runnable{
            Comsumer comsumer;
            public ConsumerMq(Comsumer comsumer){
                this.comsumer = comsumer;
            }
    
            @Override
            public void run() {
                while(true){
                    try {
                        comsumer.getMessage("Jaycekon-MQ");
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    复制代码

      运行结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    INFO | Successfully connected to tcp: //localhost:61616
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:4--->0
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-4productor:我是大帅哥,我现在正在生产东西!,count:36--->1
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:38--->2
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:37--->3
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:2--->4
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:40--->5
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:42--->6
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-4productor:我是大帅哥,我现在正在生产东西!,count:41--->7
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:1--->8
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:44--->9
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-4productor:我是大帅哥,我现在正在生产东西!,count:46--->10
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:45--->11
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:3--->12
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:48--->13
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:50--->14
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:49--->15
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-2productor:我是大帅哥,我现在正在生产东西!,count:54--->16
    Thread-2: Consumer:我是消费者,我正在消费MsgThread-5productor:我是大帅哥,我现在正在生产东西!,count:6--->17
    Thread-3: Consumer:我是消费者,我正在消费MsgThread-6productor:我是大帅哥,我现在正在生产东西!,count:52--->18
    Thread-5: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:53--->19
    Thread-4: Consumer:我是消费者,我正在消费MsgThread-3productor:我是大帅哥,我现在正在生产东西!,count:58--->20

      

      查看运行结果,我们可以做ActiveMQ 服务端:http://127.0.0.1:8161/admin/ 里面的Queues 中查看我们生产的消息。

     

     

    5、ActiveMQ的特性


     5.1 ActiveMq 的特性 

    1. 多种语言和协议编写客户端。语言: Java, C, C++, C#, Ruby, Perl, Python, PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
    2. 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
    3. 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
    4. 通过了常见J2EE服务器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
    5. 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
    6. 支持通过JDBC和journal提供高速的消息持久化
    7. 从设计上保证了高性能的集群,客户端-服务器,点对点
    8. 支持Ajax
    9. 支持与Axis的整合
    10. 可以很容易得调用内嵌JMS provider,进行测试

     

     5.2 什么情况下使用ActiveMQ?

    1. 多个项目之间集成 
      (1) 跨平台 
      (2) 多语言 
      (3) 多项目
    2. 降低系统间模块的耦合度,解耦 
      (1) 软件扩展性
    3. 系统前后端隔离 
      (1) 前后端隔离,屏蔽高安全区
    展开全文
    liqi_q 2017-11-24 09:33:31
  • 一个很简单的例子就是,在12306上面买票的时候,遇到某时刻开始抢票的时候,经常页面会弹出一个类似请稍后重试的提示,从后端的技术层面来看,大概有2层解释,第一是服务器担心扛不住瞬时的高并发流量被拖垮而快速...

    前言

    说到限流,想必大家都不陌生,一个很简单的例子就是,在12306上面买票的时候,遇到某时刻开始抢票的时候,经常页面会弹出一个类似请稍后重试的提示,从后端的技术层面来看,大概有2层解释,第一是服务器担心扛不住瞬时的高并发流量被拖垮而快速响应,另一个就是对当前的这个请求做了限流

    限流基本概念

    结合大家过往经验,不难理解“限流”的含义,对一般的限流场景来说它具有两个维度的信息:

    • 时间 限流基于某段时间范围或者某个时间点,也就是我们常说的“时间窗口”,比如对每分钟、每秒钟的时间窗口做限定
    • 资源 基于可用资源的限制,比如设定最大访问次数,或最高可用连接数

    上面两个维度结合起来看,限流就是在某个时间窗口对资源访问做限制,比如设定每秒最多100个访问请求。但在真正的场景里,我们不止设置一种限流规则,而是会设置多个限流规则共同作用,主要的几种限流规则如下:

    在这里插入图片描述

    QPS和连接数控制

    对于图中连接数和QPS)限流来说,我们可设定IP维度的限流,也可以设置基于单个服务器的限流。

    在真实环境中通常会设置多

    展开全文
    zhangcongyi420 2020-09-20 11:43:42
  • 一、场景描述 很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统。 也就是面对大流量时,如何进行流量控制? 服务接口...

    一、场景描述                                                                                             

         很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统。

        也就是面对大流量时,如何进行流量控制?

        服务接口的流量控制策略:分流、降级、限流等。本文讨论下限流策略,虽然降低了服务接口的访问频率和并发量,却换取服务接口和业务应用系统的高可用。

         实际场景中常用的限流策略:

    • Nginx前端限流

             按照一定的规则如帐号、IP、系统调用逻辑等在Nginx层面做限流

    • 业务应用系统限流

            1、客户端限流

            2、服务端限流

    • 数据库限流

            红线区,力保数据库

    二、常用的限流算法                                                                                    

         常用的限流算法由:楼桶算法和令牌桶算法。本文不具体的详细说明两种算法的原理,原理会在接下来的文章中做说明。

         1、漏桶算法

             漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:

       

             可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。

             因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率.因此,漏桶算法对于存在突发特性的流量来说缺乏效率.

         2、令牌桶算法

             令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.

     

      令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.

    三、基于Redis功能的实现                                                                            

           简陋的设计思路:假设一个用户(用IP判断)每分钟访问某一个服务接口的次数不能超过10次,那么我们可以在Redis中创建一个键,并此时我们就设置键的过期时间为60秒,每一个用户对此服务接口的访问就把键值加1,在60秒内当键值增加到10的时候,就禁止访问服务接口。在某种场景中添加访问时间间隔还是很有必要的。

          1)使用Redis的incr命令,将计数器作为Lua脚本         

    [java]  view plain  copy
    1. local current  
    2. current = redis.call("incr",KEYS[1])  
    3. if tonumber(current) == 1 then  
    4.      redis.call("expire",KEYS[1],1)  
    5.  end  

            Lua脚本在Redis中运行,保证了incr和expire两个操作的原子性。

           2)使用Reids的列表结构代替incr命令

            

    [java]  view plain  copy
    1. FUNCTION LIMIT_API_CALL(ip)  
    2. current = LLEN(ip)  
    3. IF current > 10 THEN  
    4.     ERROR "too many requests per second"  
    5. ELSE  
    6.     IF EXISTS(ip) == FALSE  
    7.         MULTI  
    8.             RPUSH(ip,ip)  
    9.             EXPIRE(ip,1)  
    10.         EXEC  
    11.     ELSE  
    12.         RPUSHX(ip,ip)  
    13.     END  
    14.     PERFORM_API_CALL()  
    15. END  

             Rate Limit使用Redis的列表作为容器,LLEN用于对访问次数的检查,一个事物中包含了RPUSH和EXPIRE两个命令,用于在第一次执行计数是创建列表并设置过期时间,

        RPUSHX在后续的计数操作中进行增加操作。

    四、基于令牌桶算法的实现                                                                           

           令牌桶算法可以很好的支撑突然额流量的变化即满令牌桶数的峰值。

    [java]  view plain  copy
    1. import java.io.BufferedWriter;  
    2. import java.io.FileOutputStream;  
    3. import java.io.IOException;  
    4. import java.io.OutputStreamWriter;  
    5. import java.util.Random;  
    6. import java.util.concurrent.ArrayBlockingQueue;  
    7. import java.util.concurrent.Executors;  
    8. import java.util.concurrent.ScheduledExecutorService;  
    9. import java.util.concurrent.TimeUnit;  
    10. import java.util.concurrent.locks.ReentrantLock;  
    11.    
    12. import com.google.common.base.Preconditions;  
    13. import com.netease.datastream.util.framework.LifeCycle;  
    14.    
    15.  20 public class TokenBucket implements LifeCycle {  
    16.    
    17. // 默认桶大小个数 即最大瞬间流量是64M  
    18.  private static final int DEFAULT_BUCKET_SIZE = 1024 * 1024 * 64;  
    19.    
    20. // 一个桶的单位是1字节  
    21.  private int everyTokenSize = 1;  
    22.    
    23. // 瞬间最大流量  
    24.  private int maxFlowRate;  
    25.    
    26. // 平均流量  
    27.  private int avgFlowRate;  
    28.    
    29. // 队列来缓存桶数量:最大的流量峰值就是 = everyTokenSize*DEFAULT_BUCKET_SIZE 64M = 1 * 1024 * 1024 * 64  
    30.  private ArrayBlockingQueue<Byte> tokenQueue = new ArrayBlockingQueue<Byte>(DEFAULT_BUCKET_SIZE);  
    31.    
    32. private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();  
    33.    
    34. private volatile boolean isStart = false;  
    35.    
    36. private ReentrantLock lock = new ReentrantLock(true);  
    37.    
    38. private static final byte A_CHAR = 'a';  
    39.    
    40. public TokenBucket() {  
    41.  }  
    42.    
    43. public TokenBucket(int maxFlowRate, int avgFlowRate) {  
    44.  this.maxFlowRate = maxFlowRate;  
    45.  this.avgFlowRate = avgFlowRate;  
    46.  }  
    47.    
    48. public TokenBucket(int everyTokenSize, int maxFlowRate, int avgFlowRate) {  
    49.  this.everyTokenSize = everyTokenSize;  
    50.  this.maxFlowRate = maxFlowRate;  
    51.  this.avgFlowRate = avgFlowRate;  
    52.  }  
    53.    
    54. public void addTokens(Integer tokenNum) {  
    55.    
    56. // 若是桶已经满了,就不再家如新的令牌  
    57.  for (int i = 0; i < tokenNum; i++) {  
    58.  tokenQueue.offer(Byte.valueOf(A_CHAR));  
    59.  }  
    60.  }  
    61.    
    62. public TokenBucket build() {  
    63.    
    64. start();  
    65.  return this;  
    66.  }  
    67.    
    68. /** 
    69.  * 获取足够的令牌个数 
    70.  * 
    71.  * @return 
    72.  */  
    73.  public boolean getTokens(byte[] dataSize) {  
    74.    
    75. Preconditions.checkNotNull(dataSize);  
    76.  Preconditions.checkArgument(isStart, "please invoke start method first !");  
    77.    
    78. int needTokenNum = dataSize.length / everyTokenSize + 1;// 传输内容大小对应的桶个数  
    79.    
    80. final ReentrantLock lock = this.lock;  
    81.  lock.lock();  
    82.  try {  
    83.  boolean result = needTokenNum <= tokenQueue.size(); // 是否存在足够的桶数量  
    84.  if (!result) {  
    85.  return false;  
    86.  }  
    87.    
    88. int tokenCount = 0;  
    89.  for (int i = 0; i < needTokenNum; i++) {  
    90.  Byte poll = tokenQueue.poll();  
    91.  if (poll != null) {  
    92.  tokenCount++;  
    93.  }  
    94.  }  
    95.    
    96. return tokenCount == needTokenNum;  
    97.  } finally {  
    98.  lock.unlock();  
    99.  }  
    100.  }  
    101.    
    102. @Override  
    103.  public void start() {  
    104.    
    105. // 初始化桶队列大小  
    106.  if (maxFlowRate != 0) {  
    107.  tokenQueue = new ArrayBlockingQueue<Byte>(maxFlowRate);  
    108.  }  
    109.    
    110. // 初始化令牌生产者  
    111.  TokenProducer tokenProducer = new TokenProducer(avgFlowRate, this);  
    112.  scheduledExecutorService.scheduleAtFixedRate(tokenProducer, 01, TimeUnit.SECONDS);  
    113.  isStart = true;  
    114.    
    115. }  
    116.    
    117. @Override  
    118.  public void stop() {  
    119.  isStart = false;  
    120.  scheduledExecutorService.shutdown();  
    121.  }  
    122.    
    123. @Override  
    124.  public boolean isStarted() {  
    125.  return isStart;  
    126.  }  
    127.    
    128. class TokenProducer implements Runnable {  
    129.    
    130. private int avgFlowRate;  
    131.  private TokenBucket tokenBucket;  
    132.    
    133. public TokenProducer(int avgFlowRate, TokenBucket tokenBucket) {  
    134.  this.avgFlowRate = avgFlowRate;  
    135.  this.tokenBucket = tokenBucket;  
    136.  }  
    137.    
    138. @Override  
    139.  public void run() {  
    140.  tokenBucket.addTokens(avgFlowRate);  
    141.  }  
    142.  }  
    143.    
    144. public static TokenBucket newBuilder() {  
    145.  return new TokenBucket();  
    146.  }  
    147.    
    148. public TokenBucket everyTokenSize(int everyTokenSize) {  
    149.  this.everyTokenSize = everyTokenSize;  
    150.  return this;  
    151.  }  
    152.    
    153. public TokenBucket maxFlowRate(int maxFlowRate) {  
    154.  this.maxFlowRate = maxFlowRate;  
    155.  return this;  
    156.  }  
    157.    
    158. public TokenBucket avgFlowRate(int avgFlowRate) {  
    159.  this.avgFlowRate = avgFlowRate;  
    160.  return this;  
    161.  }  
    162.    
    163. private String stringCopy(String data, int copyNum) {  
    164.    
    165. StringBuilder sbuilder = new StringBuilder(data.length() * copyNum);  
    166.    
    167. for (int i = 0; i < copyNum; i++) {  
    168.  sbuilder.append(data);  
    169.  }  
    170.    
    171. return sbuilder.toString();  
    172.    
    173. }  
    174.    
    175. public static void main(String[] args) throws IOException, InterruptedException {  
    176.    
    177. tokenTest();  
    178.  }  
    179.    
    180. private static void arrayTest() {  
    181.  ArrayBlockingQueue<Integer> tokenQueue = new ArrayBlockingQueue<Integer>(10);  
    182.  tokenQueue.offer(1);  
    183.  tokenQueue.offer(1);  
    184.  tokenQueue.offer(1);  
    185.  System.out.println(tokenQueue.size());  
    186.  System.out.println(tokenQueue.remainingCapacity());  
    187.  }  
    188.    
    189. private static void tokenTest() throws InterruptedException, IOException {  
    190.  TokenBucket tokenBucket = TokenBucket.newBuilder().avgFlowRate(512).maxFlowRate(1024).build();  
    191.    
    192. BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/tmp/ds_test")));  
    193.  String data = "xxxx";// 四个字节  
    194.  for (int i = 1; i <= 1000; i++) {  
    195.    
    196. Random random = new Random();  
    197.  int i1 = random.nextInt(100);  
    198.  boolean tokens = tokenBucket.getTokens(tokenBucket.stringCopy(data, i1).getBytes());  
    199.  TimeUnit.MILLISECONDS.sleep(100);  
    200.  if (tokens) {  
    201.  bufferedWriter.write("token pass --- index:" + i1);  
    202.  System.out.println("token pass --- index:" + i1);  
    203.  } else {  
    204.  bufferedWriter.write("token rejuect --- index" + i1);  
    205.  System.out.println("token rejuect --- index" + i1);  
    206.  }  
    207.    
    208. bufferedWriter.newLine();  
    209.  bufferedWriter.flush();  
    210.  }  
    211.    
    212. bufferedWriter.close();  
    213.  }  
    214.    
    215. }  


    五、示例                                                                                                

    RateLimiter 使用Demo

    [java]  view plain  copy
    1. package ratelimite;    
    2.     
    3. import com.google.common.util.concurrent.RateLimiter;    
    4.      
    5. public class RateLimiterDemo {    
    6.     public static void main(String[] args) {    
    7.         testNoRateLimiter();    
    8.         testWithRateLimiter();    
    9.     }    
    10.      
    11.     public static void testNoRateLimiter() {    
    12.         Long start = System.currentTimeMillis();    
    13.         for (int i = 0; i < 10; i++) {    
    14.             System.out.println("call execute.." + i);    
    15.                 
    16.         }    
    17.         Long end = System.currentTimeMillis();    
    18.             
    19.         System.out.println(end - start);    
    20.             
    21.     }    
    22.         
    23.     public static void testWithRateLimiter() {    
    24.         Long start = System.currentTimeMillis();    
    25.         RateLimiter limiter = RateLimiter.create(10.0); // 每秒不超过10个任务被提交    
    26.         for (int i = 0; i < 10; i++) {    
    27.             limiter.acquire(); // 请求RateLimiter, 超过permits会被阻塞    
    28.             System.out.println("call execute.." + i);    
    29.                 
    30.         }    
    31.         Long end = System.currentTimeMillis();    
    32.             
    33.         System.out.println(end - start);    
    34.             
    35.     }    
    36.         
    37. }    
    38.      

    五、  Guava并发:ListenableFuture与RateLimiter示例                                    

    概念

            ListenableFuture顾名思义就是可以监听的Future,它是对Java原生Future的扩展增强。我们知道Future表示一个异步计算任务,当任务完成时可以得到计算结果。如果我们希望一旦计算完成就拿到结果展示给用户或者做另外的计算,就必须使用另一个线程不断的查询计算状态。这样做,代码复杂,而且效率低下。使用ListenableFuture Guava帮我们检测Future是否完成了,如果完成就自动调用回调函数,这样可以减少并发程序的复杂度。      

            推荐使用第二种方法,因为第二种方法可以直接得到Future的返回值,或者处理错误情况。本质上第二种方法是通过调动第一种方法实现的,做了进一步的封装。

    另外ListenableFuture还有其他几种内置实现:

    1. SettableFuture:不需要实现一个方法来计算返回值,而只需要返回一个固定值来做为返回值,可以通过程序设置此Future的返回值或者异常信息

    2. CheckedFuture: 这是一个继承自ListenableFuture接口,他提供了checkedGet()方法,此方法在Future执行发生异常时,可以抛出指定类型的异常。

    示例

    [java]  view plain  copy
    1. import java.util.concurrent.Callable;  
    2.   
    3. import java.util.concurrent.ExecutionException;  
    4.   
    5. import java.util.concurrent.Executors;  
    6.   
    7. import java.util.concurrent.TimeUnit;  
    8.   
    9.    
    10.   
    11. import com.google.common.util.concurrent.FutureCallback;  
    12.   
    13. import com.google.common.util.concurrent.Futures;  
    14.   
    15. import com.google.common.util.concurrent.ListenableFuture;  
    16.   
    17. import com.google.common.util.concurrent.ListeningExecutorService;  
    18.   
    19. import com.google.common.util.concurrent.MoreExecutors;  
    20.   
    21. import com.google.common.util.concurrent.RateLimiter;  
    22.   
    23.    
    24.   
    25. public class ListenableFutureDemo {  
    26.   
    27.     public static void main(String[] args) {  
    28.   
    29.         testRateLimiter();  
    30.   
    31.         testListenableFuture();  
    32.   
    33.     }  
    34.   
    35.    
    36.   
    37.     /** 
    38.  
    39.      * RateLimiter类似于JDK的信号量Semphore,他用来限制对资源并发访问的线程数 
    40.  
    41.      */  
    42.   
    43.     public static void testRateLimiter() {  
    44.   
    45.         ListeningExecutorService executorService = MoreExecutors  
    46.   
    47.                 .listeningDecorator(Executors.newCachedThreadPool());  
    48.   
    49.    
    50.   
    51.         RateLimiter limiter = RateLimiter.create(5.0); // 每秒不超过4个任务被提交  
    52.   
    53.    
    54.   
    55.         for (int i = 0; i < 10; i++) {  
    56.   
    57.             limiter.acquire(); // 请求RateLimiter, 超过permits会被阻塞  
    58.   
    59.    
    60.   
    61.             final ListenableFuture<Integer> listenableFuture = executorService  
    62.   
    63.                     .submit(new Task("is "+ i));  
    64.   
    65.         }  
    66.   
    67.     }  
    68.   
    69.    
    70.   
    71.     public static void testListenableFuture() {  
    72.   
    73.         ListeningExecutorService executorService = MoreExecutors  
    74.   
    75.                 .listeningDecorator(Executors.newCachedThreadPool());  
    76.   
    77.    
    78.   
    79.         final ListenableFuture<Integer> listenableFuture = executorService  
    80.   
    81.                 .submit(new Task("testListenableFuture"));  
    82.   
    83.    
    84.   
    85.            
    86.   
    87.         //同步获取调用结果  
    88.   
    89.         try {  
    90.   
    91.             System.out.println(listenableFuture.get());  
    92.   
    93.         } catch (InterruptedException e1) {  
    94.   
    95.             e1.printStackTrace();  
    96.   
    97.         } catch (ExecutionException e1) {  
    98.   
    99.             e1.printStackTrace();  
    100.   
    101.         }  
    102.   
    103.            
    104.   
    105.         //第一种方式  
    106.   
    107.         listenableFuture.addListener(new Runnable() {  
    108.   
    109.             @Override  
    110.   
    111.             public void run() {  
    112.   
    113.                 try {  
    114.   
    115.                     System.out.println("get listenable future's result "  
    116.   
    117.                             + listenableFuture.get());  
    118.   
    119.                 } catch (InterruptedException e) {  
    120.   
    121.                     e.printStackTrace();  
    122.   
    123.                 } catch (ExecutionException e) {  
    124.   
    125.                     e.printStackTrace();  
    126.   
    127.                 }  
    128.   
    129.             }  
    130.   
    131.         }, executorService);  
    132.   
    133.    
    134.   
    135.         //第二种方式  
    136.   
    137.         Futures.addCallback(listenableFuture, new FutureCallback<Integer>() {  
    138.   
    139.             @Override  
    140.   
    141.             public void onSuccess(Integer result) {  
    142.   
    143.                 System.out  
    144.   
    145.                         .println("get listenable future's result with callback "  
    146.   
    147.                                 + result);  
    148.   
    149.             }  
    150.   
    151.    
    152.   
    153.             @Override  
    154.   
    155.             public void onFailure(Throwable t) {  
    156.   
    157.                 t.printStackTrace();  
    158.   
    159.             }  
    160.   
    161.         });  
    162.   
    163.     }  
    164.   
    165. }  
    166.   
    167.    
    168.   
    169. class Task implements Callable<Integer> {  
    170.   
    171.     String str;  
    172.   
    173.     public Task(String str){  
    174.   
    175.         this.str = str;  
    176.   
    177.     }  
    178.   
    179.     @Override  
    180.   
    181.     public Integer call() throws Exception {  
    182.   
    183.         System.out.println("call execute.." + str);  
    184.   
    185.         TimeUnit.SECONDS.sleep(1);  
    186.   
    187.         return 7;  
    188.   
    189.     }  
    190.   
    191. }  

    guava版本

    [java]  view plain  copy
    1. <dependency>  
    2.   
    3.             <groupId>com.google.guava</groupId>  
    4.   
    5.             <artifactId>guava</artifactId>  
    6.   
    7.             <version>14.0.1</version>  
    8.   
    9.         </dependency>  
    展开全文
    jek123456 2018-04-01 12:10:44
  • zengxiantao1994 2019-07-04 17:22:37
  • songfeihu0810232 2017-11-27 20:28:12
  • liuerchong 2020-08-02 20:58:01
  • ybhuangfugui 2021-04-28 00:13:29
  • qq_33206732 2018-05-29 17:16:19
  • penngo 2018-10-18 16:09:30
  • 5星
    173B qq_33705529 2018-12-11 17:07:42
  • m0_37907797 2020-01-18 12:22:30
  • higherzjm 2020-10-04 11:05:14
  • 13.73MB w549859793 2016-07-13 10:11:08
  • troyaninpc 2018-03-07 20:55:23
  • weixin_38405253 2018-03-14 12:37:10
  • 609KB zhuguang_2016 2018-04-25 20:28:30
  • m0_37907797 2021-09-08 13:42:04
  • m0_37732829 2018-06-22 15:32:45
  • 13.73MB u013589443 2016-08-31 09:16:25
  • guorui_java 2021-01-09 16:20:53
  • smilehappiness 2021-08-11 20:54:39
  • u014106644 2018-12-25 09:23:31
  • hollis_chuang 2020-04-13 09:50:27
  • 3星
    68B tzs_1041218129 2016-01-03 17:37:40
  • qq_40456064 2020-07-19 11:42:00
  • qq_42829628 2020-09-03 11:24:10
  • weixin_48364455 2020-11-03 17:37:32

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,742
精华内容 10,296
关键字:

java常用流量控制结构

java 订阅