面试话术

部署activemq

1.上传 2.解压 tar vxzf apache-activemq 3.放到一个新的文件夹下 :mv apache-activemq(要放得文件) activemq(文件夹名称) 4.启动mq须要在bin下,因此先进到bin下 5.启动:./activemq java -version 查看jdk版本前端

部署zookeeper

1.上传 (直接拉过来) 2.解压 tar vxzf zookeeper... 3.在conf中 复制zoo_sample.cfg 具体代码:cp zoo_sample.cfg zoo.cfg 4.编辑zoo.cfg 修改路径 完成以后,wq保存退出 5.在zookeeper下建立一个文件夹date mkdir data 6.给zookeeper-3.4起别名 zookeeper3.4 zookeeper 7.而后在bin下启动就好了 启动:./zkServer.sh startjava

AOP:

代理模式:    (将被代理对象注入给代理对象,当调用代理对象时,其实是在调用被注入的被代理对象)
                        代理类     被代理类
                      
                     静态代理: 代理类只能代理某一种类,不能代理任何一个类

                     动态代理: 代理类能够代理任何一个类

实现切面的具体代码:
   注解形式:
           1.创建一个切面类  里面加上两个注解    @Component (让spring容器发现这个类)     @Aspect (告诉它这是个切面)
           2.里面写方法       方法上家注解 ,表示这是什么通知,是前置(@before),后置(@),仍是异常,环绕或最终通知  
                   还得标明要切的方法是什么,如:@before("execution(*   包名.*.*))  *为包名里的全部类(第一*),全部方法(第二*)
复制代码

1.tomcat的工做流程是什么? 2.登陆里面的token是怎么生成的?token每次是怎么样传回服务端的? 3.session共享有什么办法? 4.锁? 5.redis 缓存? 6.内存模型?mysql

1.什么是线程池,简单说一下几种常见线程池?

java线程池的工做原理和数据库链接池的差很少,由于每次从新建立线程都是很耗资源的操做,因此咱们能够创建一个线程池,这样当须要用到线程进行某些操做时,就能够直接去线程池里面找到空闲的线程,这样就能够直接使用,而不用等到用到的时候再去建立,用完以后能够把该线程从新放入线程池供其余请求使用从而提升应用程序的性能。linux

线程池的核心流程:

1.构建一个 ThreadPoolExecutor 并指定默认要建立的线程的数量 2.经过 threadPool.execute() 去添加一个个要执行的线程即实现了Runable接口的java类 3.在实现了Runable接口的java类的run方法中写入具体的业务代码nginx

线程池的业务场景:

我在工做的时候,当时一个同事给我提了一个需求,目前有大量的图片须要处理生产缩略图并进行加水印,由于按照普通的处理方法一个个的进行处理太慢了,问我有没有好的解决方案,这个时候我就想到了java中的线程池,我构建了一个线程数为5个线程池,而后采用分段批量提取的方式每500条为一组数据进行图片信息的提取,而后再把这些经过Threadpool的execute方法交给线程池中的线程进行处理,即充分使用了CPU硬件资源又加快了大数据状况下程序的处理效率。c++

我当时在工做的过程当中,认识一个作电商的朋友,他们当时公司才起步,不少技术都不成熟,因此就经常和我探讨一些技术问题,有次他向我请教一个问题,问我如何才能提升网站的性能,我根据本身在项目中的经验以及本身之前阅读的关于优化方面的资料给他提出了不少建议,如用lucene进行全文检索,用memcached进行分布式缓存,以及经过spring定时器结合freeMarker模板引擎来生成静态页面,因为要生成的页面的数量比较多,考虑到程序的性能,我建议他结合java的线程池进行工做,这样就能够充分使用了CPU硬件资源又加快了大数据状况下程序的处理效率。程序员

【线程池简述】web

线程池中,当须要使用线程时,会从线程池中获取一个空闲线程,线程完成工做时,不会直接关闭线程,而是将这个线程退回到池子,方便其它人使用。ajax

简而言之,使用线程池后,原来建立线程变成了从线程池得到空闲线程,关闭线程变成了向池子归还线程。redis

2.说一下数据库索引,什么是索引,优势和缺点和几个基本的索引类型?

索引的概念

索引就是为了提升数据的检索速度。 数据库的索引相似于书籍的索引。 在书籍中,索引容许用户没必要翻阅完整个书就能迅速地找到所须要的信息。 在数据库中,索引也容许数据库程序迅速地找到表中的数据,而没必要扫描整个数据库。

索引的优势
 建立惟一性索引,保证数据库表中每一行数据的惟一性
 大大加快数据的检索速度,这也是建立索引的最主要的缘由
 减小磁盘IO(向字典同样能够直接定位)
复制代码

索引的缺点

建立索引和维护索引要耗费时间,这种时间随着数据量的增长而增长 索引须要占用额外的物理空间 当对表中的数据进行增长、删除和修改的时候,索引也要动态的维护,下降了数据的维护速度

索引的分类

  普通索引和惟一性索引    普通索引:CREATE INDEX mycolumn_index ON mytable (myclumn)    惟一性索引:保证在索引列中的所有数据是惟一的    CREATE unique INDEX mycolumn_index ON mytable (myclumn)    单个索引和复合索引    单个索引:对单个字段创建索引    复合索引:又叫组合索引,在索引创建语句中同时包含多个字段名,    最多16个字段    CREATE INDEX name_index ON userInfo(firstname,lastname)    顺序索引,散列索引,位图索引

3.http请求中的中文乱码问题

经过浏览器访问服务器页面和资源时,不可避免地要传送中文字串,若是客户机与服务器不能用同一码表解析字串,确定会出现各     种各样的乱码问题。我总结了几个乱码场景及解决办法,以下

  服务器上的中文字串被客户端访问时出现的乱码问题
复制代码

缘由:浏览器在解析中文时,不知道该用什么码表去解析,就会用默认的gb2312去解析,确定会出现乱码

解决办法:以什么码表写入流,在响应的请求头里就告诉浏览器用什么码表,例子使用utf-8 客户端提交中文到服务端致使的乱码

缘由:客户端以UTF-8编码,服务端中的request以默认的Iso8859码表解析

解决办法:告诉request用UTF-8码表解析

多线程:

进程:当前正在运行的程序,一个应用程序在内存中的执行区域
    线程:进程中的一个执行控制单元,执行路径
            单线程:安全性高,可是效率低
            多线程:安全性低,效率高
    一个进程能够有一个线程,也能够有多个线程
CPU执行线程的随机性 (CPU高速切换致使的)
复制代码

多线程实现的方式:

方式1:一种方法是将类声明为继承Thread的子类。该子类应重写Thread类的run方法。接下来能够分配并启动该子类的实例。
复制代码

方法2:另外一种方法是声明实现Runable接口的类。该类而后实现run方法。而后能够分配该类的实例,在建立Thread时做为一个参数来传递并启动。

主方法是多线程????

答:主方法是单线程的,可是能够在主方法中建立多个线程,同事执行(变为多线程) 既然有了继承Thread为什么还要整出来实现Runable???? 答:java中是单一继承,若是一个类,继承了一个类,就不能继承其余类。若是要是实现了接口,还能够继承别的类。

(静态修饰 的方法,能够直接经过{类名。方法名}调用)
    static void  sleep (long millis)   ::让当前进程睡会
    static Thread currentThread()    ::返回当前线程对象
    Thread.currentThread().getName()    直接获取进程的名称
    void serName(String name)  改变线程名称,使之与参数name相同
复制代码

** 多个线程,一个数据,且并发访问这个数据,就容易出错. 怎么解决??? 答: 这里面须要用到一个synchronized(同步锁),能够修饰代码块和方法,被修饰的代码块和方法一旦被某一个线程访问,则直接锁住,其余的线程将没法访问。 解决1. 同步代码块:(对象锁就是一次只能进一个,别的线程都只能等) synchronized(锁对象){ 这里面是放的须要共享的代码 }

(这个):这个能够是对象锁this,也能够是类锁.class锁
复制代码

注意:锁对象须要被全部的线程付共享 同步:安全性高,效率低 异步(非同步):正好相反 安全性低,效率高 解决2. 用synchronized修改方法(放在权限修饰符以后 void以前),这个方法就变成了一个同步方法 ,也就是一个方法访问以后,其余线程都没法访问。

同步方法的: static synchronized 是类锁 synchronized 是对象锁

synchronize是一个可重如锁,就是方法里面调用方法。

对于对象,不一样的内存地址,就是不一样的对象,也是就不一样的锁。他们能够同时执行。可是同一个锁的时候,就不能够同时执行。必须一个完成以后,再执行另外一个。 (判断是不是同一个对象,不是有名称决定的,而是经过内存地址决定的)

利用实现callable来作多线程: 适用场景:适合于处理大量事务以后,须要返回数据结果的状况下。(基本数据类型不能当作泛型)


注意: 非静态 同步方法的锁对象是this 静态的同步方法的锁对象是当前类的字节码对象 同步方法:使用关键字synchronized修饰的方法,一旦被一个线程访问,则整个方法所有锁住,其余线程则没法访问

意外收获:对于sleep()方法,咱们首先知道他是属于Thread类中的。而wait()方法,则是属于Object类中的。 sleep()方法致使了程序暂停执行指定的时间,让出CPU给其余的线程,可是他的监控转态依然保持着,当指定的时间到了以后,他会自动恢复成运行状态。在调用sleep()方法的过程当中,线程不会释放对象锁。 而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行转态。 sleep()必须捕获异常,而wait,notify和notifyall不须要捕获异常。


线程的生命周期?(一个对象的生老病死)


linux讲解

1.linux操做系统比较稳定(世界级巨头计算机,各个行业软件服务器系统都是采用的这种语言,常见的就是系统开发人员,运维人员,程序开发人员) 2.要学习找资料鸟哥linux私房菜这本书可参照。

WebService && CXF的讲解

WebService是JDK自带的,至关于JDBC   (也就是 底层实现)
CXF是基于WebService的框架,至关于Hibernate/mybatis    (也就是 框架)
复制代码

讲解CVS,SVN(集中式)与Git(分布式版本控制系统)

一:Git简介

集中式版本控制系统:版本库是集中存放在中央服务器的,用时拿出来,用完再放进去 。最大的缺点就是必须联网才能工做,网慢还受影响。 分布式版本控制系统:1.它相对于集中式的来讲,没有“”中央服务器“”,因此每一个人的 电脑都是一个完整的版本库,这样工做的时候就不须要联网, 2.和集中式相比,分布式的更安全,由于每一个人电脑里都有完整的版本库,一我的的 电脑坏了,直接从别人那直接复制一个就能够了。而集中式的中央服务器要是坏了,全部人都 不能干活了。( 对了,别忘了,他仍是开源的,免费的,哈哈)。 3.在实际使用分布式版本控制系统的时候,其实不多在两人之间的电脑上推送版本库 的修改,由于可能大家俩不在一个局域网内,两台电脑互相访问不了,也可能今天 你的同事病 了,他的电脑压根没有开机。所以,分布式版本控制系统一般也有一台充当“中央服务器”的电脑,但这个服务器的做用仅仅是用来方便“交换”你们的 修改,没有它你们也一 样干活,只是交换修改不方便而已。 CVS的弊端:1.因为CVS自身设计的问题,会形成提交文件不完整,版本库莫名其妙损坏的状况。 2.一样是开源并且免费的SVN修正了CVS的一些稳定性问题,是目 前用 得最多的集中式版本库控制系统。 3.除了免费的外,还有收费的集中式版本控制系统,好比IBM的ClearCase。

二:安装

第三方登陆(话术)

第三方登陆采用国际通用的OAtuth协议。首先须要去第三方注册帐号,获取到惟一性的id和cecret安全码,而后在咱们的网站上添加第三方的登陆图标。例如QQ图标,微信什么的。接下来呢,就是一个三次握手,第一次呢就是,当用户点击这个图标时,跳转到第三方的登陆页面,用户登陆后会直接跳转到咱们的回调地址,而且发送给咱们一个code随机码。这样第一次握手就完成了。而后咱们将这个code随机码和id,seret安全码发送给第三方(利用HttpClient,发送的post请求)。这时候第三方会返回给咱们一个token令牌(其中包含了第三方的一些相关信息)。这样第二次握手就算完成了。可是此次获取到的信息通常不全,因此咱们还须要根据用户绑定的状态再一次查询。也就有了第三次握手。第三次在利用token码在发送请求。(通常是为了获取用户名,头像,性别,住址)。假如是第一次登录,咱们会给第三方发送一个绑定帐号的请求,将咱们的网站与第三方网站绑定。以后跳转到用户信息完善页面,让用户把信息补全。最后将第三方帐号信息保存到咱们本身的数据库中。假如以前登录过,那么咱们会根据用户信息到本身的数据库中查询出以前添加的信息,并保存在session中,而后跳转到首页,这样第三次握手就算完成了。也就完成了第三方帐号在咱们网站的登陆。

电商如何处理高并发的状况

处理高并发的状况,通常咱们想到的是经过分流的方式,加快系统的吞吐量,和业务的优化这三方法。在分流方面咱们采用的是用Ngnix作负载均衡和反向代理。在系统吞吐量上咱们采用的是redis作缓存处理。在文件的存储上咱们能够采用fastdfs作存储。页面呢能够用freemarker静态化技术作静态页面。与数据库有关的业务能够采用分库分表的形式,来提供数据库的效率。方法呢有不少,主要呢就是根据系统的压力和场景来选择适合本身网站的方式就能够了。

关于支付的话术

其实全部的第三方支付都差很少,就是根据他们提供额文档直接写实现本身的业务逻辑就能够了,他们的接口须要什么样的数据,就给他们什么样的数据就能够了。支付成功后会跳转到咱们的回调接口。(网站想要与第三方登陆平台对接,就须要先去该平台注册商户号以及商户秘钥)

支付宝支付:

买家点击确认付款后咱们会根据订单号去调用订单服务提供的dubbo获取该订单的信息。同时咱们会给支付宝发送一个请求,(当中包含商户号,秘钥,回调地址,加密签名(MD5加密(编号+商户号+总价格))等支付信息)。并将支付信息保存到咱们的订单表以及订单详情表中。同时页面也跳转到支付宝的支付页面。买家支付完成后,支付宝会把支付结果发送给咱们的回调地址。支付结果中会有一个通知id,咱们须要将通知id做为参数调用支付宝给咱们的支付结果查询接口。去查询支付结果是否正确。主动查询主要是为了,防止咱们的回调地址泄露。查询结果接口会给咱们返回一个以XML形式的查询信息。告诉咱们该通知id是不是以支付宝发起,而且该支付信息是否有效。咱们还须要根据用户的实际支付金额和理应支付金额作判断,若是一直,而且通知id也有效,那么久认为该用户支付成功。而后根据用户信息跳转到支付结果页面,而且更新数据库中的支付信息。这样支付就完成了。

微信支付:

订单管理

首先是订单表的设计,主要包括订单表和订单详情表,订单表主要包含订单的主要信息,好比订单的编号、总额、数量、状态、收货人信息等。其中收货人信息必需要冗余到订单表中,不能简单用Id进行管理。订单详情表和订单表是多对一关系,订单详情表主要计量订单中的商品的详细信息,这些信息也要冗余进来,不能经过id进行简单的关联,由于订单一旦生成,这些信息通常不会再容许改变。

订单在用户结算购物车时生成,若是同时购买多个商家的商品,在结算购物车时须要进行分单,同时生成多张订单。在用户中心,每一个用户均可以看到并跟踪本身的订单,进行支付、申请退货、确认收货、评价等操做。商家后台能够看到商家本身的全部订单,进行确认发货操做。而在运营管理平台,能够监控全部的订单,可是不能进行操做。

订单的状态主要包括:待支付、待发货、已发货、已完成、已取消;

生成订单时,应该对库存进行一次校验,防止超卖;

单点登陆

咱们的单点登陆系统,主要包含了登陆验证、token校验、注销、注册几大功能,单点登陆系统提供了统一的登陆和注册页面,提供了统一的登陆token校验接口。

单点登陆的主要原理就是在登陆成功之后,生成一个令牌,这个令牌要求每次登陆惟一不可重复,咱们就简单的用了一个随机的UUID,由于咱们的系统在部署时,各个模块都是经过Nginx映射到同一个一级域名下的,cookie只要把他的做用域设置成一级域名,就能够在全部同一个一级域名下的模块中共享。因此咱们把随机生成的token,以字符串 “token”为key,放在cookie里边,而后用生成的token作key,用户对象信息转成json字符串后,做为value,放到redis里边,都设置有效期30分钟;

而后作了一个统一校验token的接口;各个模块在本身的拦截器里边,调用此token校验接口,验证是否登陆,若是返回null,则说明没有登陆,拦截到统一的登陆页面,并把进入拦截到的url放入cookie里边,方便登陆成功之后,获取这个url,进行原路径跳转,而不是每次登陆都进入首页,提供用户的体验度。若是返回用户信息,则说明已经登陆,模块建立本身的session,并放行url。统一校验token的接口的主要流程是,首先从cookie里边获取到token,而后经过token到redis里边获取用户信息。这两个过程,任何一个失败,都直接返回null,若是成功,就把cookie和token的值重新设置一遍(这个是为了刷新有效期);?这样就实现了多个模块只须要登陆一次就能够的流程。

还有就是注销,注销也是调用统一的注销接口,注销时须要首先从cookie中获取token,根据token删除redis中的用户信息,而后在删除cookie中的token。

MQ消息队列

MQ简称消息队列,他是一个不一样项目之间进行通信时,对消息进行管理的组件。有了MQ,能够使项目之间交互由同步转换成异步,解耦了消息的处理过程。把消息统一管理起来,按照顺序,根据客户端的处理能力一个一个的进行操做,MQ具备送达保证、排序保证、峰值处理、异步通讯几大特性。在高并发时,对于减轻数据库压力很是有效。MQ通常有点对点和发布订阅两种方式,点对点就是一个消息只容许接收一次,发布订阅模式,一个消息能够被屡次接收。目前主流的产品有RabbitMQ、ActiveMQ和Kafka;ActiveMq是Java语言开发的,RabbitMQ是Erlang语言开发的,理论上,RabbitMQ的性能比ActiveMq更强,是非Java系统的首选,ActiveMq是Java的,整套系统若是原本就是Java的,配合的默契更佳。Kafka至关于一个分布式的MQ,传统的MQ,消息被消化掉后会被mq删除,而kafka中消息被消化后不会被删除,而是到配置的expire时间后,才删除,他把写入压力均摊到各个节点。能够经过增长节点下降压力;

anjularJS

AngularJS 是一个 JavaScript 框架。它是一个以 JavaScript 编写的库。它通常用在 数据操做比较多的应用。为了实现这些,AngularJs引入了一些很是棒的特性,包括模板机制、数据绑定、指令、依赖注入、路由等。数据绑定多是AngularJS最酷最实用的特性。经过数据与模板的绑定,可以让咱们摆脱繁琐的DOM操做,而将注意力集中在业务逻辑上。AngularJS内置了不少指令用来控制模板,如ng-repeat,ng-class等,也有不少指令来帮咱们完成业务逻辑。还有AngularJS服务啊路由之类的功能也都是很是实用的。AngularJS不依赖(也不妨碍)任何其余的框架,咱们甚至能够基于其它的框架来开发AngularJS应用。在咱们以前的一个项目中也用到了AngularJS,经过AngularJS,咱们实现了先后端分离开发,前端使用路由,页面的性能会有很大的提高,同时也会减小后端的压力,页面跳转能够不须要通过后端,后端只负责提供数据作为展现。

HTTPClient

HttpClient字面理解就是http请求的客户端,他是Apache开发的一套HTTP协议的客户端编程工具包。是纯Java语音编写的,支持https协议,实现了http的get、post、delete、put等所有方法,但咱们通常只用get和post方法,用httpclient能够直接跨域请求http协议的url,并拦截返回的响应结果。

咱们项目里边有写好的工具类,里边封装好了他的get和post方法,传入url和参数,返回String类型数据(通常是json字符串或xml字符串),而后咱们进行解析就能够了。

他的调用步骤是:

1.建立HttpClient对象。

2.建立请求方法的实例,并指定请求URL。若是须要发送GET请求,建立HttpGet对象;若是须要发送POST请求,建立HttpPost对象。

3.若是须要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。

4.调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。

5.调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可经过该对象获取服务器的响应内容。

6.释放链接。不管执行方法是否成功,都必须释放链接

Shiro

Apache Shiro是java的一个安全框架,比Spring Security要简单的多,可是没有Spring Security他的功能强大。Shiro主要有登陆认证,受权,会话管理这三大功能。另外添加了加密、缓存、web基础等功能。但它不会去维护用户和权限。这个还须要咱们本身去完成。它的基本工做流程就是:首先咱们经过SecurityUtils来获取Subject,用它来进行认证和受权,而后经过安全管理器securityManager来管理全部的Subject. 给Shiro的securityManeger中注入Realm.经过realm获取相应的用户进行比较来肯定用户身份是否合法。同时也须要中获得用户相应的角色和权限进行用户验证是否能够进行操做。框架中使用通常是,先导入相关jar包,web.xml中加shiro-filter过滤器,配置shiro.xml,里边配置过滤器和安全管理器,还能够自定义form 认证过滤器、自定义realm(领域)、加密等。他提供了多种受权方式;编程受权、注解受权、jsp标签受权。

springboot和springcloud

spring boot 我理解就是把 spring,spring-mvc,spring-data-jpa 等等的一些经常使用的经常使用的基础框架组合起来,提供默认的可插拔的设计配置。spring boot对spring的配置进行简化,几乎零配置。同时对spring 须要的jar 也进行了整合,解决jar冲突的问题。能够理解为springMvc的升级版。提供了spring-boot-starter-parent的整合工具包。集成了它之后,项目中大部分jar包就再也不引用了。内置了Tomcat插件,能够直接用main方法运行;

spring_cloud是基于spring_boot的微服务分布式架构,他主要包括:

服务注册中心:Eureka Server 服务注册者客户端:Eureka Client 服务消费端:负载均衡客户端:ribbon和feign 断路器Hystrix 路由网关zuul(Zuul的主要功能是路由转发和过滤器,zuul默认和Ribbon结合实现了负载均衡的功能。)

事务的隔离级别

脏读:一个事务看到了另外一个事务没有提交的更新数据。
     不可重复:在同一事物中,屡次读取数据可是返回不一样的结果。
     幻读:一个事务在执行过程当中读取到另外一个事务已提交的插入数据。这是并发形成的。
复制代码

事务的传播特性

  1. requierd: 若是当前没有事务,就新建一个事务,若是有事务,就加入这个事务中。
  2. requierd_new: 新建事务,若是当前有事务,就把当前事务挂起。
  3. supports: 支持当前事务,若是当前没有事务,就以非事务方法执行。
  4. not_supports: 就以非事务方法执行,若是当前存在事务,就把事务挂起。
  5. mandatory: 使用当前事务,若是没有当前事务就抛异常。
  6. never: 就以非事务方法执行,若是有事务就抛异常。
  7. nested: 若是当前存在事务,就嵌套在事务内执行。若是当前没有事务,就执行与 required相似的操做(至关于若是没有就是默认required)。 required(必修的) mandatory(强制性的) nested(嵌套的)

利用docker部署(基本话术)

利用docker作项目部署,首先得知道Dockerfile,dockerfile其实就是一些脚本,就是能把代码变成镜像的一种脚本。他和maven插件的功能是同样的。这须要好几步才能实现,因此为了方便,又须要借助jenkins,jenkins算是一种工具,他把dockerfile的步骤放进了jenkins中,而后只须要一个按钮,就能实现dockerfile的功能。因此只要配好了jenkins是就方便了好多。二Gogs是jenkins中的一个东西。比较难懂的一个。

Nginx负载均衡是怎么搭建的?

首先,在linux下装一个Nginx,必需要有依赖,如:prce正则依赖。还有pcc,c++等。依赖都配置好后才能够装nginx。Nginx集群主要是nginx.conf中配置,conf中的service中location下的proxy_pass配置一个tomcat服务中的引用,另外还要配置一个upstream中ip地址端口号,service中tomcat的引用的是upstream的名字。另外,负载均衡实在upstream中配置,来引用的tomcat的IP地址和端口号后面跟一些参数,来配置权重,参数有weigt,backup等等。

session共享是怎么作的?

使用Nginx作的反向代理。session共享实现有多种方式,好比能够本身写一个filter来拦截请求,而后从请求中取得session的id,而后根据session的id在缓存中查找对应的session。可是我用的是spring对session的管理。实际上spring对session的管理也是基于filter实现的。(若是细问怎么作的,就这样回答:1.先导入依赖。2.在web.xml中配置一个filter的过滤器。3.在spring配置文件中,配置spring对session管理的实现。4.把redis集成在项目)

JVM

堆: 分为两部分新生代和老年代(老年代:须要长时间保留的;新生代:用完就得销毁的) 都会先放在新生代中,等到他年龄大的必定的时候,就会放在老年代中(经历了不少次都没有被清理的) 新生代的扫描策略和老年代的扫描策略是不同的。 新生代:能够分为三部分(伊甸园,S0(From),S1(To)) 根据执行GC()的次数, S0,S1是两块大小相等,功能相同的内存空间。同一时间,只能有一个在(使用)运行转态。(为了时刻都在 紧挨着) 栈: 一个栈有三部分:(局部变量表,操做数栈和帧数据区)

java虚拟机原理:系统虚拟机和程序虚拟机 虚拟机的结构:类加载子系统,堆,栈,直接内存,方法区,本地方法栈,执行引擎,垃圾回收机制,PC收集器

重要的一些概念:

  1. 在java中对象实例都是在堆中建立的,一些类信息,常量,和静态变量回放在方法区中,这个堆和方法区都是线程共享的。 2.GC机制是有JVM提供的,用来清理须要清理的对象,回收堆内存的。 3.GC机制是将java程序员从内存管理中解放出来的,因此它更关注于业务逻辑。 4.在java中,GC是有一个叫垃圾回收器的守护线程所执行的。 5.在内存中回收一个对象,首先就须要调用finalize()方法。 6.做为一个java程序员,不能强制JVM执行GC,这个是由堆内存的大小决定的。 7.System.gc()和Runtime.gc()会向JVM发送执行GC的请求,可是JVM不必定会执行。 8.若是堆没有新的内存建立新的对象了,那么会抛出OutOfMemoryError.

哪些对象回呗GC回收呢???

通常GC须要有三件事须要作:1.那些对象须要被回收 2.什么时候回收这些对象 3.采用什么样的方式能够回收(常见的有引用计数法) 引用计数法:给对象添加一个引用计数器,每当有一个地方引用了,计数器就+1,当引用失效后,计数器就-1;在任什么时候候计数器都为0时,就表示这个对象不可能被使用。 当一个对象经过一系列的根对象都不可达时就会被回收。通俗易懂的就是:当一个对象的全部引用都为null.

GC的算法有哪些?

1.复制算法:就是有两个相同的区域,每次只使用一个其中一个(堆中的年轻代的处理方法就是复制算法) 2.标记清除算法:就是先标记处全部须要回收的对象,而后统一回收。 3.标记整理算法:就是先标记出全部须要的回收对象,只不过是先整理一遍,就是让全部存活的对象都向一端移动,而后清理。

SQL的优化

致使查询慢的缘由:

1.数据量过大
2.表设计不合理
3.sql语句写的很差
4.没有合理使用索引
复制代码

针对sql语句的优化:

1.查询中不适用*
2.尽可能减小子查询,使用关联查询(left join,right join  等等)替代
3.合理的增长冗余字段
4.建表的时候能使用数字类型的字段就使用数字类型字段,由于数字类型的字段比字符类型的要查询起来快的多。
5.哪些能够过滤掉最大数量记录的条件必须写在where字句的最末尾
复制代码

说索引前,显了解一下这个explain(查看sql的执行计划):

最终要的就是:
select_type:sql语句的难易程度;
type:表示表的链接类型(ALL:说明对表进行了完成的)
rows:查询是受影响的行数。
复制代码

补充: (使用explain查看sql执行计划后,咱们主要先看下type属性,表示链接的类型,若是是ALL这种那就须要优化了, 再看下possible_key属性,表示能够使用的索引,若是没有则为null,key属性表示mysql实际决定使用的索引,若是没有选择索引,键是null, rows 表示mysql认为它执行查询时必须检查的行数,行数越多效率越低。)

索引的类型:通常分为:主键索引,惟一索引,组合索引,普通索引。 什么是索引:数据库索引是数据库管理系统中的一个排序的数据结构,以协助快速查询,更新数据 库表中数据,索引的实现一般使用B树(B-tree)以及其变种B+tree(一些高效率的算法)

注意事项:

一、使用like关键字模糊查询时,% 放在前面索引不起做用,只有“%”不在第一个位置,索引才会生效(like '%文'--索引不起做用) 二、使用联合索引时,只有查询条件中使用了这些字段中的第一个字段,索引才会生效 三、使用OR关键字的查询,查询语句的查询条件中只有OR关键字,且OR先后的两个条件中的列都是索引时,索引才会生效,不然索引不生效。 四、尽可能避免在where子句中使用!=或<>操做符,不然引擎将放弃使用索引而进行全表扫描。 五、对查询进行优化,应尽可能避免全表扫描,首先应考虑在where以及order by涉及的列上创建索引。 六、应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。如:   select id from t where num/2=100   应改成:   select id from t where num=100*2 七、尽可能避免在where子句中对字段进行函数操做,将致使引擎放弃使用索引而进行全表扫描。 八、不要在 where 子句中的“=”左边进行函数、算术运算或其余表达式运算,不然系统将可能没法正确使用索引。 九、并非全部的索引对查询都有效,sql是根据表中的数据来进行查询优化的,当索引列有大量数据重复时,sql查询不会去利用索引,如一表中有字段   sex,male,female几乎个一半,那么即便在sex上创建了索引也对查询效率起不了做用。 十、索引并非越多越好,索引当然能够提升相应的 select 的效率,但同时也下降了 insert 及 update 的效率,   由于 insert 或 update 时有可能会重建索引,因此怎样建索引须要慎重考虑,视具体状况而定。一个表的索引数最好不要超过6个,   若太多则应考虑一些不常使用到的列上建的索引是否有 必要。 十一、尽可能使用数字型字段,若只含数值信息的字段尽可能不要设计为字符型,这会下降查询和链接的性能,并会增长存储开销。   这是由于引擎在处理查询和链接时会 逐个比较字符串中每个字符,而对于数字型而言只须要比较一次就够了。 十二、mysql查询只使用一个索引,所以若是where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。    所以数据库默认排序能够符合要求的状况下不要使用排序操做,尽可能不要包含多个列的排序,若是须要最好给这些列建复合索引。 1三、order by 索引 ,不起做用的问题(除了主键索引以外):   一、 若是select 只查询索引字段,order by 索引字段会用到索引,要否则就是全表排列;

   二、若是有where 条件,好比where vtype=1 order by vtype asc . 这样order by 也会用到索引!

总结(优化数据库的八种方法): 1.选取最适用的字段属性 2.使用链接(join)来代替子查询。 3.使用联合(UNION)来代替手动建立的临时表 4.事务 5.锁定表 6.使用外键 7.使用索引 8.优化的查询语句

死锁

什么是死锁?

标准定义:
  本身的理解:一座独木桥上有两辆车,此刻都在桥上(谁也不能前进,谁也不能后退),就这样耗着。造成死局面。
复制代码

产生死锁的必要条件:

1.互斥条件:如独木桥就是一种独占资源,两方的人不能同时过桥。
  2.不可抢占条件:如过独木桥的人不能强迫对方后退,也不能非法地将对方推下桥,必须是桥上的人本身过桥后空出桥面(即主动释放占有资源),对方的人才能过桥。
  3.占有且申请条件:甲过不去,前进不能,又不后退;乙也处于一样的情况。
  4.循环等待条件:就像前面的过独木桥问题,甲等待乙占有的桥面,而乙又等待甲占有的桥面,从而彼此循环等待。
复制代码

死锁的预防:

方法:只要破坏了前面提到的四个必要条件中的任意一个条件,死锁就不会发生。(通常地,解决死锁的方法分为死锁的预防,避免,检测与恢复三种) 具体方法:也就是打破四个必要因素。 死锁的恢复: 一旦在死锁检测时发现了死锁,就要消除死锁,使系统从死锁状态中恢复过来。

(1)最简单,最经常使用的方法就是进行系统的从新启动,不过这种方法代价很大,它意味着在这以前全部的进程已经完成的计算工做都将付之东流,包括参与死锁的那些进程,以及未参与死锁的进程。

(2)撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。这时又分两种状况:一次性撤消参与死锁的所有进程,剥夺所有资源;或者逐步撤消参与死锁的进程,逐步收回死锁进程占有的资源。通常来讲,选择逐步撤消的进程时要按照必定的原则进行,目的是撤消那些代价最小的进程,好比按进程的优先级肯定进程的代价;考虑进程运行时的代价和与此进程相关的外部做业的代价等因素。 
复制代码

此外,还有进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处,并由此点处继续执行,以求再次执行时再也不发生死锁。虽然这是个较理想的办法,可是操做起来系统开销极大,要有堆栈这样的机构记录进程的每一步变化,以便从此的回退,有时这是没法作到的。

搜索引擎——solr

什么是solr?

solr是一个开源的搜索平台,用于构建搜索应程序。它创建在Lucene(全文搜索引擎)之上。solr是企业级的,快速的和高度可扩展的。

Maven

Maven是一个项目管理工具,其核心特色就是经过maven能够进行包的依赖管理,保证jar包版本的一致性,以及能够使多个项目共享jar包,从而可以在开发大型应用的时候,减少项目的规模。

为了节省下jar包的时间?咱们能够采用了nexus搭建了在局域网内的maven私服,而后经过配置settings.xml中创建mirror镜像,将全部下载jar包的请求都转发到maven私服上,以后经过在pom.xml,及中配置项目所依赖的jar包,从而达到在构建项目的时候,先从本地仓库中查找,若是不存在从内部私服查找,若是不存在最后再从外网central服务器查找的机制,达到了节省下载宽带,提升开发效率,以及jar包重用的目的。

spring中的IOC和AOP(话术)

IOC: ioc另一种说话叫作DI,既依赖注入。它并非一种技术实现,而是一种设计思想。在任何一个实际开发意义的程序项目中,咱们会使用不少的类来描述他们特有的功能,而且经过类与类之间的相互协做来完成特定的业务逻辑。这个时候,每一个类都须要负责管理与本身有交互的类的引用和依赖。这时候代码将变得异常难易维护和极度的高耦合。而IOC的出现真实来解决这个问题的。咱们经过IOC将这些相互依赖对象的建立、协调工作交给spring容器来处理,每一个对象只须要关注其自身的业务逻辑就能够了。在遮掩那个的角度上来看,得到依赖的对象方式,进行了反转,变成了与spring容器控制对象如歌获取外部资源。(举例:就是头疼病人去医院买药的例子。本身选药很难受,因此就直接找医生,让医生配药,直接吃就好。IOC起到的就是医生的做用,他收集你的需求要需,而且对症下药。直接开药给你。你就是对象,药品就是你所须要的外部资源。)

什么是AOP? 面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面 1.面向切面编程提供声明式事务管理 2.spring支持用户自定义的切面

面向切面编程(aop)是对面向对象编程(oop)的补充, 面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。 AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象, 是对应用执行过程当中的步骤进行抽象,,从而得到步骤之间的逻辑划分。

aop框架具备的两个特征: 1.各个步骤之间的良好隔离性 2.源代码无关性

Spring的事务管理机制实现的原理,就是经过这样一个动态代理对全部须要事务管理的Bean进行加载,并根据配置在invoke方法中对当前调用的 方法名进行断定,并在method.invoke方法先后为其加上合适的事务管理代码,这样就实现了Spring式的事务管理。Spring中的AOP实 现更为复杂和灵活,不过基本原理是一致的。

Lucene原理

Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。lucene 可以为文本类型的数据创建索引,因此你只要能把你要索引的数据格式转化的文本的,Lucene 就能对你的文档进行索引和搜索。好比你要对一些 HTML 文档,PDF 文档进行索引的话你就首先须要把 HTML 文档和 PDF 文档转化成文本格式的,而后将转化后的内容交给 Lucene 进行索引,而后把建立好的索引文件保存到磁盘或者内存中,最后根据用户输入的查询条件在索引文件上进行查询。

索引和搜索: Lucene 采用的是一种称为反向索引(inverted index)的机制。反向索引就是说咱们维护了一个词 / 短语表,对于这个表中的每一个词 / 短语,都有一个链表描述了有哪些文档包含了这个词 / 短语。这样在用户输入查询条件的时候,就能很是快的获得搜索结果。搜索引擎首先会对搜索的关键词进行解析,而后再在创建好的索引上面进行查找,最终返回和用户输入的关键词相关联的文档。对于中文用户来讲,最关心的问题是其是否支持中文的全文检索。因为Lucene良好架构设计,对中文的支持只需对其语言词法分析接口进行扩展就能实现对中文检索的支持。

索引步骤: 1.获取内容:lucene做为一款核心搜索库,不提供任何功能来实现内容获取。利用大量的开源爬虫软件实现这个功能 2.创建文档:获取原始内容后,须要对这些内容进行索引,必须将这些内容转换成部件(文档)。文档主要包括几个带值的域,好比标题,正文,摘要,做者和连接。若是文档和域比较重要的话,还能够添加权值。 3.文档分析:搜索引擎不能直接对文本进行索引:必须将文本分割成一系列被称为语汇单元的独立的原子元素。每个语汇单元能大体与语言中的“单词”对应起来,这个步骤决定文档中的文本域如何分割成语汇单元系列。lucene提供了大量内嵌的分析器能够轻松控制这步操做。 4.文档索引:将文档加入到索引列表中。Lucene在这一步骤中提供了强档的API,只需简单调用提供的几个方法就能够实现出文档索引的创建。为了提供好的用户体验,索引是必需要处理好的一环:在设计和定制索引程序时必须围绕如何提升用户的搜索体验来进行。

Elasticsearch简介:

Elasticsearch是一个实时的分布式搜索和分析引擎。它能够帮助你用史无前例的速度去处理大规模数据。它能够用于全文搜索,结构化搜索以及分析,固然你也能够将这三者进行组合。

ES的优势:

1.Elasticsearch是分布式的。不须要其余组件,分发是实时的。 2.Elasticsearch 彻底支持 Apache Lucene 的接近实时的搜索。 ES的缺点: 1.只有一个开发者。 2.还不够自动。

Solrs简介:

Solr是最流行的企业级搜索引擎。Solr是用Java编写、运行在Servlet容器。的一个独立的全文搜索服务器。Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索,并具备相似REST的HTTP/XML和JSON的API。Solr强大的外部配置功能使得无需进行Java编码,即可对 其进行调整以适应多种类型的应用程序。Solr有一个插件架构,以支持更多的高级定制。
复制代码

优势:

1.Solr有一个更大、更成熟的用户、开发和贡献者社区。 2.支持添加多种格式的索引,如:HTML、PDF、微软 Office 系列软件格式以及 JSON、XML、CSV 等纯文本格式。 3.Solr比较成熟、稳定。 4.不考虑建索引的同时进行搜索,速度更快。 缺点: 1.创建索引时,搜索效率降低,实时索引搜索效率不高。 2.当单纯的对已有数据进行搜索时,Solr更快。 3.当实时创建索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具备明显的优点。 4.随着数据量的增长,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。 5.综上所述,Solr的架构不适合实时搜索的应用。

Elasticsearch 与 Solr 的比较总结:

1.两者安装都很简单; 2.Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能; 3.Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式; 4.Solr 官方提供的功能更多,而 Elasticsearch 自己更注重于核心功能,高级功能多有第三方插件提供; 5.Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch。 6.Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。

*****************************************mongodb简介 MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构很是松散,是相似json的bson格式,所以能够存储比较复杂的数据类型。Mongo最大的特色是它支持的查询语言很是强大,其语法有点相似于面向对象的查询语言,几乎能够实现相似关系数据库单表查询的绝大部分功能,并且还支持对数据创建索引。 特色: 1.它的特色是高性能、易部署、易使用,存储数据很是方便。 2.模式自由。 3.支持动态查询。 4.支持彻底索引,包含内部对象。 5.支持查询。 6.支持复制和故障恢复。 7.使用高效的二进制数据存储,包括大型对象(如视频等)。 使用原理: 所谓“面向集合”(Collection-Oriented),意思是数据被分组存储在数据集中,被称为一个集合(Collection)。每一个集合在数据库中都有一个惟一的标识名,而且能够包含无限数目的文档。集合的概念相似关系型数据库(RDBMS)里的表(table),不一样的是它不须要定义任何模式(schema)。Nytro MegaRAID技术中的闪存高速缓存算法,可以快速识别数据库内大数据集中的热数据,提供一致的性能改进。 MongoDB适用的场景: 1.网站实时数据处理:Mongo 很是适合实时的插入,更新与查询,并具有网站实时数据存储所需的复制及高度伸缩性。 2.缓存:因为性能很高,Mongo 也适合做为信息基础设施的缓存层。在系统重启以后,由Mongo 搭建的持久化缓存层能够避免下层的数据源过载。 3.高伸缩性的场景:Mongo 很是适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持。 MongoDB不适用的场景: 1.要求高度事务性的系统。 2.传统的商业智能应用。 3.复杂的跨文档级联查询。

数据模型:一个MongoDB 实例能够包含一组数据库,一个DataBase 能够包含一组Collection(集合),一个集合能够包含一组Document(文档)。一个Document包含一组field(字段),每个字段都是一个key/value pair。 key: 必须为字符串类型。 value:能够包含以下类型。 ● 基本类型,例如,string,int,float,timestamp,binary 等类型。 ● 一个document。 ● 数组类型。

**********************************************Websocket(HTML5出的东西) 要想了解websocket,咱们首先须要了解http协议。websocket是一个新协议,跟http协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是它是HTTP协议上的一种补充。有交集可是并非所有。

Wrbsocket的优势:持久性,被动性(就是服务器能够主动给客户推送消息了,HTTP不能够。)

介绍Websocket以前须要先说一下这个,long poll和ajax的原理。 ajax轮询(须要更快的速度):让浏览器隔几秒就发送一次请求,询问服务器是否有新信息。 long poll(须要更多的电话):它的原理跟 ajax轮询 差很少,都是采用轮询的方式,不过采起的是阻塞模型(一直 打电话,没收到就不挂电话),也就是说,客户端发起链接后,若是没消息,就一直不返回Response给客户端。 直到有消息才返回,返回完以后,客户端再次创建链接,周而复始。

Websocket的做用:

只要websocket链接成功后,以后就能够源源不断的传递消息了;只须要确认一次身份信息,就不再用了。比http要效率高,这也就是他的持久性。
 被动性就是,就是websocket链接成功后,服务端能够直接给客户端推送消息,而传统的http是不能够的。
复制代码

传统的HTTP协议是无转态的。

Websocket的工做流程:

浏览器经过JavaScript向服务端发出创建WebSocket链接的请求,在WebSocket链接创建成功后,客户端和服务端就能够经过 TCP链接传输数据。由于WebSocket链接本质上是TCP链接,不须要每次传输都带上重复的头部数据,因此它的数据传输量比轮询和Comet技术小 了不少。本文不详
复制代码

细地介绍WebSocket规范,主要介绍下WebSocket在Java Web中的实现。

Websocket里面的注解: @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, 11 * 注解的值将被用于监听用户链接的终端访问URL地址,客户端能够经过这个URL来链接到WebSocket服务器端

分布式事务

正常的:就是用的事务管理器(transactionManager)
复制代码

在分布式的项目里,用的是分布式事务管理。不一样的框架,使用不一样的分布式事务。dubbo框架、springcloud等框架。不一样的框架,解决方案不同。 Springcloud框架,利用lcn来处理分布式事务。利用redis作事务的解决。微服务在每次操做的时候,都须要在redis在存放一个标识符。等所有都完成以后,就提交。 dubbo框架:利用transaction这个中间件来实现分布式事务。还有一种方法就是经过RocketMQ,利用其它的MQ也是能够的。

Hashtable与ConcurrentHashMap的区别

众所周知,Hashtable是安全的,可是效率低下。而ConcurrentHashMap在这两方面都挺好的。这是为何呢? HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的状况下HashTable的效率很是低下。由于当一个线程访问HashTable的同步方法时,其余线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,而且也不能使用get方法来获取元素,因此竞争越激烈效率越低。 HashTable容器在竞争激烈的并发环境下表现出效率低下的缘由,是由于全部访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不一样数据段的数据时,线程间就不会存在锁竞争,从而能够有效的提升并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分红一段一段的存储,而后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其余段的数据也能被其余线程访问。

ConcurrentHashMap的结构分析

ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap相似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每一个HashEntry是一个链表结构的元素, 每一个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先得到它对应的Segment锁。
复制代码

HashMap的讲解

1.HashMap是基于数组和单向链表的。在这里在解释一下什么是单向链表。就是只有下一个(next),没有上一个。具体的就是总共有(next,key,value,entity)这四个。 2.在这里必定要清楚HashMap怎么存值。他是单向链表,通俗易懂的说就是一个链里套了另外一个链。新添的数据老是在最外层。最先的数据都在链表的最里层。 3.还有就是一个扩容,HashMap扩容是根据负载因子决定的。通常负载因子默认是0.75。总数据的长度*0.75就是扩容节点。但在这里必定要记得,并非确定到了这个时候都须要扩容。还得根据有没有影响HashMap的总体效率。若是影响了,则扩容。若是没有影响,就不扩容。(拿在这里就要问,怎么样才算应算效率了呢。那么首先得知道,HashMap查询是怎么查的。他是根据数组的链的长度决定的。链的长度越短,效率越高。因此假若有一个数组还为空*****,而其余的数组上链表的长度没有变化,是不影响整个HashMap的效率的)2

HashMap与Hashtable的区别

1.HashMap是不安全的,而Hashtable是安全的。(主要是由于Hashtable每一个方法上都有synchronized) 2.HashMap有且容许一个key为null,value能够为多个,而Hashtable里面不能够为null。 3.就是数组的长度不同。HashMap默认是16,而Hashtable是11。

相关文章
相关标签/搜索