公司名称:西安华仪电气有限公司 公司地址:西安高陵县陕西省西安市高陵区榆楚镇仁马路陕汽重卡斜对面 西安华仪电气有限公司 公司规模:100-200人面试整体事项
一.IO:
1)bio,nio,aio的区别;
同步阻塞IO(JAVA BIO): 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
同步非阻塞IO(Java NIO) : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。用户进程也需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问。
异步阻塞IO(Java NIO): 此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为什么说是阻塞的呢?因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄(如果从UNP的角度看,select属于同步操作。因为select之后,进程还需要读写数据),从而提高系统的并发性!
2)nio框架:dubbo的实现原理;
dubbo作为rpc框架,实现的效果就是调用远程的方法就像在本地调用一样。如何做到呢?就是本地有对远程方法的描述,包括方法名、参数、返回值,在dubbo中是远程和本地使用同样的接口;然后呢,要有对网络通信的封装,要对调用方来说通信细节是完全不可见的,网络通信要做的就是将调用方法的属性通过一定的协议(简单来说就是消息格式)传递到服务端;服务端按照协议解析出调用的信息;执行相应的方法;在将方法的返回值通过协议传递给客户端;客户端再解析;在调用方式上又可以分为同步调用和异步调用;简单来说基本就这个过程
3)京东内部的jsf是使用的什么协议通讯:可参见dubbo的协议;
二.算法:
1)java中常说的堆和栈,分别是什么数据结构;另外,为什么要分为堆和栈来存储数据。
2)TreeMap如何插入数据:二叉树的左旋,右旋,双旋;
3)一个排序之后的数组,插入数据,可以使用什么方法?答:二分法;问:时间复杂度是多少?
4)平衡二叉树的时间复杂度;
5)Hash算法和二叉树算法分别什么时候用;
6)图的广度优先算法和深度优先算法:详见jvm中垃圾回收实现;
三.多线程相关:
1)说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行);
2)进程通讯的方式:消息队列,共享内存,信号量,socket通讯等;
3)用过并发包的哪些类;
4)什么地方用了多线程;
5)Excutors可以产生哪些线程池;
1、创建固定数目线程的线程池。 public static ExecutorService newFixedThreadPool(int nThreads)
优点:线程数可控,可以根据系统资源,设置线程数。 缺点:线程数固定,没有任务时一样占用资源。且超过最大线程数时,提交的任务会被阻塞,直到有空闲线程。 2、创建一个可缓存的线程池,调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。 public static ExecutorService newCachedThreadPool()
优点:不活动的线程会被关闭来释放资源,且新任务不会被阻塞 缺点:任务较多且周期较长时,会占用大量系统资源。 3、创建一个单线程化的 Executor。 public static ExecutorService newSingleThreadExecutor()
特点:依次执行线程,可以控制任务执行顺序。针对特殊场景使用 4、创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代 Timer 类。 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
特点:用于创建定时任务。
6)为什么要用线程池;
1:提高效率 创建好一定数量的线程放在池中,等需要使用的时候就从池中拿一个,这要比需要的时候创建一个线程对象要快的多。
2:方便管理 可以编写线程池管理代码对池中的线程统一进行管理,比如说系统启动时由该程序创建100个线程,每当有请求的时候,就分配一个线程去工作, 如果刚好并发有101个请求,那多出的这一个请求可以排队等候,避免因无休止的创建线程导致系统崩溃
7)volatile关键字的用法:使多线程中的变量可见;
四.数据库相关(mysql):
1)msyql优化经验:
1. 为查询缓存优化你的查询
2 当只要一行数据时使用 LIMIT 1
3为搜索字段建索引
4. 在Join表的时候使用相当类型的例,并将其索引 6.避免 SELECT * 7. 尽可能的使用 NOT NULL 8. 选择正确的存储引擎
2)mysql的语句优化,使用什么工具;
3)mysql的索引分类:B+,hash;什么情况用什么索引;
4)mysql的存储引擎有哪些,区别是什么;
5)说说事务的特性和隔离级别;
事务,其定义是应用程序中一系列不可分割的操作,就是一组可以完成某个业务的代码集合,在关系数据库中,事务可以是一条SQL语句,或者一组SQL语句,亦或整个程序。
其中事务有四个特征,必须同时满足这四个特征才是一个完整的事务。即事务的ACID特性:
原子性(Atomicity):
即事务是数据库的不可分割单元,事务内的操作要么全部执行完成,如果有一个失败,则事务内的操作全部失败。
一致性(consistency):
即事务必须使数据库从一个一致性状态变成另外一个一致性状态,原子性和一致性是密切相关的。
隔离性(isolation):
即事务和事务之间没有影响关系,这个事务的执行不能被其它事务所干扰。并发执行的各个事务不能互相干扰,具有隔离性。
持久性(durability):
如果事务对数据库进行了操作并进行了提交,则数据库对此的改变应该具有持久性,不能因为其它操作或者数据库的损坏而丢失数据。故事务应该具有持久性。
这是事务的四大特性,在并发情况下,事务会产生以下问题:
更新丢失:
两个事务都对同一行数据进行更新,但是第二组事务因为某种原因而中途即退出,所以导致两个事务对数据的修改都失败。
脏读:
一个事务读取了另一个事务没有提交的数据叫做脏读。例如,A事务正在修改数据,但是还没有修改完毕进行提交,这个过程中B事务对这条数据进行了读取操作,B事务产生了脏读。
不可重复读:
一个事务在对数据库进行了再次查询操作,但是即产生了不同结果,数据本身产生了变化,此为不可重复读。例如,A事务第一次查询此条数据,而B事务对此条数据进行了修改,而后A事务又再次查询了此条数据,却不是预期的结果,不能重复读取。故不可重复读(进行了UPDATE操作)。 幻读: 一个事务在对数据库进行了再次查询操作,但是却产生了不同结果,或是少了数据行,或是多了未知数据行,此为幻读(一定要明白是数据条数,不是数据本身)。例如,A事务第一次查询此条数据,而B事务对此表进行了插入或者删除操作,而后A事务又再次查询了此表,却产生了与上次不一样的条数记录。故为幻读(进行了INSERT/DELETE操作)。
为了解决以上问题,所以引出了事务的隔离级别:
读未提交:
在该隔离级别,所有事务都可以看到其它事务未提交的内容数据,此隔离级别没有解决任何并发问题,故在应用场景中不常用。
读已提交:
在该隔离级别,一个事务只能读取其它事务已经提交的内容数据,此隔离级别解决了脏读,但没有解决不可重复读和幻读,是ORACLE的默认隔离级别。
可重复读:
在该隔离级别,能保证一个事务之间的多个实例在并发能读取同一数据,此隔离级别解决了脏读和不可重复读,是MYSQL的默认级别。
串行化:
这是最高的隔离级别,在此隔离级别,事务事务之间只能顺序执行,使之没有任何冲突,也就 是从而解决了脏读,不可重复读和幻读,此隔离级别效率较慢,并且有较多的超时现象。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发的效率就越低。一般情况下,采用读已提交或者可重复读,它能够有效避免脏读和不可重复读。
6)悲观锁和乐观锁的区别,怎么实现;
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
五.mq:
1)mq的原理是什么:有点大。。都可以说;
在介绍activemq之前,先简单介绍JMS,它是J2EE的13个规范之一,提供的是消息中间件的规范。
JMS包括以下基本构件:
连接工厂,是客户用来创建连接的对象,ActiveMQ提供的是ActiveMQConnectionFactory;
连接connection;
会话session,是发送和接收消息的上下文,用于创建消息生产者,消息消费者,相比rocketMQ会话session是提供事务性的;
目的地destination,指定生产消息的目的地和消费消息的来源对象;
生产者、消费者,由会话创建的对象,顾名思义。
消息通信机制
点对点模式,每个消息只有1个消费者,它的目的地称为queue队列;
发布/订阅模式,每个消息可以有多个消费者,而且订阅一个主题的消费者,只能消费自它订阅之后发布的消息。
消息确认机制
Session.AUTO_ACKNOWLEDGE,直接使用receive方法。 Session.CLIENT_ACKNOWLEDGE,通过消息的acknowledge 方法确认消息。 Session.DUPS_ACKNOWLEDGE,该选择只是会话迟钝第确认消息的提交。如果JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么JMS provider 必须把消息头的JMSRedelivered 字段设置为true。
原理很多,但是把原理映射在实践中,就更容易懂了。一起看看下面的这个小例子,通过代码回想原理,最后运行显示到控制台上,验证结论。
2)mq如何保证实时性;
MQ为了保证消息必达,消息上下半场均可能发送重复消息,如何保证消息的幂等性呢
上半场,MQ-server生成inner-msg-id,保证上半场幂等 此ID全局唯一,业务无关,由MQ保证,对上下MQ-client屏蔽 下半场,由发送方带入biz-id 业务方接受并判断重复问题,保证幂等,这个ID对单业务唯一,业务相关,对MQ透明 结论 幂等性,不仅对MQ有要求,对业务上下游也有要求
3)mq的持久化是怎么做的;
ActiveMQ持久化方式:AMQ、KahaDB、JDBC、LevelDB。
六.nosql相关(主要是redis): 1)redis和memcache的区别;
Redis中,并不是所有的数据都一直存储在内存中的,这是和Memcache相比一个最大的区别。 Redis在很多方面具备数据库的特征,或者说就是一个数据库系统,而Memcache只是简单的K/V缓存。 他们的扩展都需要做集群;实现方式:master-slave、Hash。 在100k以上的数据中,Memcache性能要高于Redis。 如果要说内存使用效率,使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcache。当然,这和你的应用场景和数据特性有关。 如果你对数据持久化和数据同步有所要求,那么推荐你选择Redis,因为这两个特性Memcache都不具备。即使你只是希望在升级或者重启系统后缓存数据不会丢失,选择Redis也是明智的。 Redis和Memcache在写入性能上面差别不大,读取性能上面尤其是批量读取性能上面Memcache更强 共同点:Memcache,Redis 都是内存数据库
2)用redis做过什么;
3)redis是如何持久化的:rdb和aof;
4)redis集群如何同步;
5)redis的数据添加过程是怎样的:哈希槽;
6)redis的淘汰策略有哪些;
6)redis的淘汰策略有哪些;
volatile-lru:从已设置过期时间的数据集(server.db.expires)中挑选最近最少使用的数据淘汰 volatile-ttl:从已设置过期时间的数据集(server.db.expires)中挑选将要过期的数据淘汰 volatile-random:从已设置过期时间的数据集(server.db.expires)中任意选择数据淘汰 allkeys-lru:从数据集(server.db.dict)中挑选最近最少使用的数据淘汰 allkeys-random:从数据集(server.db.dict)中任意选择数据淘汰 no-enviction(驱逐):禁止驱逐数据
7)redis有哪些数据结构;
String字符串 List列表 Set集合 Hash散列 Zset有序集合
七.zookeeper:
1)zookeeper是什么;
ZooKeeper是一个集中式服务,用于维护配置信息,命名,提供分布式同步和提供组服务。所有这些类型的服务以分布式应用程序的某种形式或另一种形式使用。每次他们被实现,有很多工作,以修复错误和竞争条件是不可避免的。由于实现这些服务的难度,应用程序最初通常嘲弄它们,这使得它们在变化的存在下变得脆弱并且难以管理。即使正确地完成,这些服务的不同实施导致在应用被部署时的管理复杂性
2)zookeeper哪里用到;
3)zookeeper的选主过程;
以一个简单的例子来说明整个选举的过程. 假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器依序启动,来看看会发生什么. 1) 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态 2) 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态. 3) 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader. 4) 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了. 5) 服务器5启动,同4一样,当小弟. 以上就是fastleader算法的简要分析,还有一些异常情况的处理,比如某台服务器宕机之后的处理,当leader宕机之后的处理等等,后面再谈.
4)zookeeper集群之间如何通讯;
5)你们的zookeeper的节点加密是用的什么方式;
6)分布式锁的实现过程;
使用Zookeeper实现分布式锁的优点
有效的解决单点问题,不可重入问题,非阻塞问题以及锁无法释放的问题。实现起来较为简单。
使用Zookeeper实现分布式锁的缺点
性能上不如使用缓存实现分布式锁。 需要对ZK的原理有所了解。
八.linux相关:
1)linux常用的命令有哪些;
mkdir 建立目录 mkdir -p 建立多级目录 touch 建立文件
2)如何获取java进程的pid;
3)如何获取某个进程的网络端口号;
4)如何实时打印日志;
5)如何统计某个字符串行数;
|