2019为面试总结面试题

1.开发中Java用了比较多的数据结构有哪些?

 

 

 

java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类;

List

List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下 >标)来访问List中的元素,这类似于Java的数组。 

Vector

基于数组(Array)的List,其实就是封装了数组所不具备的一些功能方便我们使用,所以它难易避免数组的限制,同时性能也不可能超越数组。所以,在可能的情况下,我们要多运用数组。另外很重要的一点就是Vector是线程同步的(sychronized)的,这也是Vector和ArrayList 的一个的重要区别。

ArrayList

同Vector一样是一个基于数组上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector好一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。

LinkedList

LinkedList不同于前面两种List,它不是基于数组的,所以不受数组性能的限制。 
它每一个节点(Node)都包含两方面的内容: 
1.节点本身的数据(data); 
2.下一个节点的信息(nextNode)。 
所以当对LinkedList做添加,删除动作的时候就不用像基于数组的ArrayList一样,必须进行大量的数据移动。只要更改nextNode的相关信息就可以实现了,这是LinkedList的优势。

List总结

  • 所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ]
  • 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ]
  • 所有的List中可以有null元素,例如[ tom,null,1 ]

     基于Array的List(Vector,ArrayList)适合查询,而LinkedList 适合添加,删除操作

Set(Set是不包含重复元素的Collection)

HashSet

虽然Set同List都实现了Collection接口,但是他们的实现方式却大不一样。List基本上都是以Array为基础。但是Set则是在 HashMap的基础上来实现的,这个就是Set和List的根本区别。HashSet的存储方式是把HashMap中的Key作为Set的对应存储项。看看 HashSet的add(Object obj)方法的实现就可以一目了然了。

LinkedHashSet

HashSet的一个子类,一个链表。

SortedSet

有序的Set,通过SortedMap来实现的。

Set总结:

1)Set实现的基础是Map(HashMap)(2)Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象

 

HashMap

API ----基于Hash表的Map  接口实现。此实现提供所有可选的映射操作,并允许  值和    键。(  HashMap 类大致相当于Hashtable,除了它是不同步的并且允许空值。)这个类不保证地图的顺序; 特别是,它不保证订单会随着时间的推移保持不变。  

TreeMap

API ----基于红黑树的 NavigableMap  实现。地图根据 其键的 自然顺序进行排序 ,或者 Comparator  根据使用的构造函数在地图创建时提供。 
TreeMap则是对键按序存放,因此它便有一些扩展的方法,比如firstKey(),lastKey()等,你还可以从TreeMap中指定一个范围以取得其子Map。 
键和值的关联很简单,用put(Object key,Object value)方法即可将一个键与一个值对象相关联。用get(Object key)可得到与此key对象所对应的值对象。 
 
HashMap:适用于在Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)
 
一、几个常用类的区别 
1.ArrayList: 元素单个,效率高,多用于查询 
2.Vector: 元素单个,线程安全,多用于查询 
3.LinkedList:元素单个,多用于插入和删除 
4.HashMap: 元素成对,元素可为空 
5.HashTable: 元素成对,线程安全,元素不可为空 
二、Vector、ArrayList和LinkedList 
大多数情况下,从性能上来说ArrayList最好,但是当集合内的元素需要频繁插入、删除时LinkedList会有比较好的表现,但是它们三个性能都比不上数组,另外Vector是线程同步的。所以: 
如果能用数组的时候(元素类型固定,数组长度固定),请尽量使用数组来代替List; 
如果没有频繁的删除插入操作,又不用考虑多线程问题,优先选择ArrayList; 
如果在多线程条件下使用,可以考虑Vector; 
如果需要频繁地删除插入,LinkedList就有了用武之地; 
如果你什么都不知道,用ArrayList没错。 
 
谈谈你对HashMap的理解,底层原理的基本实现,HashMap怎么解决碰撞问题的?
https://blog.csdn.net/weixin_37751634/article/details/82882222
 
http协议,get和post的基本区别?
  • get(默认值)是通过URL传递表单值,数据追加在action属性后面。
  • post传递的表单值是隐藏到http报文体中,url中看不到。
  • get是通过url传递表单值,post通过url看不到表单域的值;
  • get传递的数据量是有限的,如果要传递大数据量不能用get,比如type=“file”上传文章、type=“password”传递密码或者<textarea>发表大段文章,post则没有这个限制。
  • post区别:网址隐藏;只要当前页面请求是POST请求,那么刷新就是重新发出POST,部分浏览器会提示“是否重复提交”。
  • 只要在地址栏中输入一个网址回车访问,那么就是GET。精确到具体网页

数据格式。服务端文件名后跟着“?”,由于客户端可能向服务器端提交多个键值对,键值对之间用“&”进行分割,如果URL中有汉字、特殊符号等,则需要对URL进行编码。

Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,删4个操作。 我们最常见的就是GET和POST了。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息.

我们看看GET和POST的区别

1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456.(注意对于用户登录来说,get是不安全的,网页直接显示你的用户名和密码) POST方法是把提交的数据放在HTTP包的Body中.

2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.

3. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。

4. GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.

tcp/ip协议,三次握手,窗口滑动机制:

 https://www.cnblogs.com/wen-ge/articles/5819778.html

悲观锁和乐观锁问题使用场景?

悲观锁:比较适合写入操作比较频繁的场景,如果出现大量的读取操作,每次读取的时候都会进行加锁,这样会增加大量的锁的开销,降低了系统的吞吐量。

乐观锁:比较适合读取操作比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的重新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量。

总结:两种所各有优缺点,读取频繁使用乐观锁,写入频繁使用悲观锁。

分布式session的几种实现方式

第一种:粘性session

原理:粘性Session是指将用户锁定到某一个服务器上,比如上面说的例子,用户第一次请求时,负载均衡器将用户的请求转发到了A服务器上,如果负载均衡器设置了粘性Session的话,那么用户以后的每次请求都会转发到A服务器上,相当于把用户和A服务器粘到了一块,这就是粘性Session机制。

优点:简单,不需要对session做任何处理。

缺点:缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的session信息都将失效。

适用场景:发生故障对客户产生的影响较小;服务器发生故障是低概率事件。

第二种:服务器session复制

原理:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要session,以此来保证Session同步。

优点:可容错,各个服务器间session能够实时响应。

第三种:session共享机制

使用分布式缓存方案比如memcachedRedis,但是要求Memcached或Redis必须是集群。

使用Session共享也分两种机制,两种情况如下:

① 粘性session处理方式

原理:不同的 tomcat指定访问不同的主memcached。多个Memcached之间信息是同步的,能主从备份和高可用。用户访问时首先在tomcat中创建session,然后将session复制一份放到它对应的memcahed上。memcache只起备份作用,读写都在tomcat上。当某一个tomcat挂掉后,集群将用户的访问定位到备tomcat上,然后根据cookie中存储的SessionId找session,找不到时,再去相应的memcached上去session,找到之后将其复制到备tomcat上。

② 非粘性session处理方式

原理:memcached做主从复制,写入session都往从memcached服务上写,读取都从主memcached读取,tomcat本身不存储session

缺点:会对网络负荷造成一定压力,如果session量大的话可能会造成网络堵塞,拖慢服务器性能。

JVM老年代和新生代的比例?2:1

JVM虚拟机 YGC和FGC发生的具体场景

1、YGC和FGC是什么 

   YGC :对新生代堆进行gc。频率比较高,因为大部分对象的存活寿命较短,在新生代里被回收。性能耗费较小。

   FGC :全堆范围的gc。默认堆空间使用到达80%(可调整)的时候会触发fgc。

2、什么时候执行YGC和FGC

   1、eden空间不足,执行 young gc

   2、old空间不足,perm空间不足,调用方法System.gc() ,ygc时的悲观策略, dump live的内存信息时(jmap –dump:live),都会执行full gc

如何保证共享变量修改时的原子性?

使用synchronized(低效,使用悲观锁)、volatile修饰符来保证变量的可见性

Jdk5后提出了atomic 原子操作也可以保证可见性(高效且不需要使用同步,基于CAS)

Volatile和synchronized区别:

Volatile只是保证变量可见性,并不能确保原子性,它是依赖CPU提供的特殊指令内存屏障指令来控制可见性,被Volatile修饰的成员变量在被线程访问时在读操作前会强行插入一条内存屏障读指令强行从主存中读取(让高速缓存中的数据失效,重新从主内存加载数据),变量在被线程修改时会在写指令之后插入写屏障,让写入缓存的最新数据写回到主内存。

不能确保原子性,是因为如果A线程和B线程同时读取到变量a值,A线程修改a后将值刷到主存、同时B线程也修改了a的值并刷到主存,这时候B线程就覆盖了A线程修改操作。

Synchronized是通过对线程加锁(独占锁)控制线程同步,被Synchronized修饰的内存只允许一个线程访问

线程池的构造类的方法的5个参数的具体意义?

corePoolSize
核心线程数,核心线程会一直存活,即使没有任务需要处理。当线程数小于核心线程数时,即使现有的线程空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。

核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认情况下不会退出。

maxPoolSize
当线程数大于或等于核心线程,且任务队列已满时,线程池会创建新的线程,直到线程数量达到maxPoolSize。如果线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常。
keepAliveTime
当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。

allowCoreThreadTimeout
是否允许核心线程空闲退出,默认值为false。

queueCapacity
任务队列容量。从maxPoolSize的描述上可以看出,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设置。

详细见:https://blog.csdn.net/u011109589/article/details/80532796

单机上一个线程正在处理服务,如果忽然断电了怎么办

我们可以对正在处理和阻塞队列的任务做事物管理或者对阻塞队列中的任务持久化处理,并且当断电或者系统崩溃,操作无法继续下去的时候,可以通过回溯日志的方式来撤销正在处理的已经执行成功的操作。然后重新执行整个阻塞队列。

阻塞队列持久化,正在处理事物控制。断电之后正在处理的回滚,日志恢复该次操作。服务器重启后阻塞队列中的数据再加载

 防止接口重复请求

1.在data里定义一个初始状态,设为false,作为加载标志

2.请求之前将状态变成true,再去请求接口,这时一直是加载状态

3.当接口响应之后不管是成功还是失败都将状态变成false

4.每次请求之前都判断一下加载状态,如果是true直接return

 
 

 

转载于:https://www.cnblogs.com/chen-ya-ping/p/10514702.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值