笔试真题
![640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/7f14e57e10763ec82dd03970794584f9.jpeg)
![640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/0a3ba4d8cc747face0d50fc6e7036074.jpeg)
![640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/7a292e605d65b8c335e7157ba04d7b1b.jpeg)
![640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/5593c561f86895a678946f9d537abc0d.jpeg)
![640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/ea541d1a58dfe32edbec0cd4474c8caf.jpeg)
面试过程
1: 请问 ArrayList、 HashSet、 HashMap 是线程安全的吗?如果不是我想要线程安全的集合怎么办?
我们都看过上面那些集合的源码(如果没有那就看看吧),每个方法都没有加锁,显然都是线程不安全的。话又说过来如果他们安全了也就没第二问了。
在集合中 Vector 和 HashTable 倒是线程安全的。你打开源码会发现其实就是把各自核心方法添加上了synchronized 关键字。
Collections 工具类提供了相关的 API,可以让上面那 3 个不安全的集合变为安全的。
①// Collections.synchronizedCollection(c)
②// Collections.synchronizedList(list)
③ // Collections.synchronizedMap(m)
④ // Collections.synchronizedSet(s)
上面几个函数都有对应的返回值类型,传入什么类型返回什么类型。打开源码其实实现原理非常简单,就是将集合的核心方法添加上了 synchronized 关键字。
2: 阿帕奇提供的StringUtils中 isNotEmpty 和isNotBlank的区别?
1)public static boolean isEmpty(String str) 判断某字符串是否为空,为空的标准是str==null或str.length()==0
示例:
StringUtils.isEmpty(null) ==> true
StringUtils.isEmpty("") ==> true
StringUtils.isEmpty(" ") ==> false //注意StringUtils 中空格作非空处理
StringUtils.isEmpty(" ") ==> false
StringUtils.isEmpty("bob") ==> false
StringUtils.isEmpty(" bob ") ==> false
2)public static boolean isNotEmpty(String str) 判断某字符串是否非空,等于!isEmpty(String str)
示例:
StringUtils.isNotEmpty(null) ==> false
StringUtils.isNotEmpty("") ==> false
StringUtils.isNotEmpty(" ") ==> true
StringUtils.isNotEmpty(" ") ==> true
StringUtils.isNotEmpty("bob") ==> true
StringUtils.isNotEmpty(" bob ") ==> true
3)public static boolean isBlank(String str) 判断某字符串是否为空或长度为0或由空白符(whitespace)构成
示例:
StringUtils.isBlank(null) ==> true
StringUtils.isBlank("") ==> true
StringUtils.isBlank(" ") ==> true
StringUtils.isBlank(" ") ==> true
StringUtils.isBlank("\t \n \f \r") ==> true //对于制表符、换行符、换页符和回车符,均识为空白符
StringUtils.isBlank("\b") ==> false //"\b"为单词边界符
StringUtils.isBlank("bob") ==> false
StringUtils.isBlank(" bob ") ==> false
4)public static boolean isNotBlank(String str) 判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成,等于!isBlank(String str)
示例:
StringUtils.isNotBlank(null) ==> false
StringUtils.isNotBlank("") ==> false
StringUtils.isNotBlank(" ") ==> false
StringUtils.isNotBlank(" ") ==> false
StringUtils.isNotBlank("\t \n \f \r") ==> false
StringUtils.isNotBlank("\b") ==> true
StringUtils.isNotBlank("bob") ==> true
StringUtils.isNotBlank(" bob ") ==> true
3: Spring 的通知是什么?有哪几种类型?
page通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 SpringAOP 框架触发的代码段。
Spring 切面可以应用五种类型的通知:
1) before:前置通知,在一个方法执行前被调用。
2) after: 在方法执行之后调用的通知,无论方法执行是否成功。
3) after-returning: 仅当方法成功完成后执行的通知。
4) after-throwing: 在方法抛出异常退出时执行的通知。
5) around: 在方法执行之前和之后调用的通知。
4: 简单介绍一下 Shiro 框架 ?
A:栈Apache Shiro 是 Java 的一个安全框架。使用 shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE环境,也可以用在 JavaEE 环境。 Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。
三个核心组件: Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户” 。但是,在 Shiro 中, Subject 这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西” 。但考虑到大多数目的和用途,你可以把它认为是 Shiro 的“用户” 概念。
Subject 代表了当前用户的安全操作, SecurityManager 则管理所有用户的安全操作。
SecurityManager:它是 Shiro 框架的核心,典型的 Facade 模式, Shiro 通过SecurityManager 来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm 充当了 Shiro 与应用安全数据间的“桥梁” 或者“连接器” 。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时, Shiro 会从应用配置的 Realm 中查找用户及其权限信息。
5: Mybatis 中一级缓存与二级缓存 ?
①一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或close 之后,该 Session 中的所有 Cache 就将清空。
② 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache, HashMap 存储,不同在于其存储作用域为Mapper(Namespace),并且可自定义存储源,如 Ehcache。作用域为 namespance 是指对该 namespance 对应的配置文件中所有的 select 操作结果都缓存,这样不同线程之间就可以共用二级缓存。启动二级缓存:在 mapper 配置文件中: <cache />。
二级缓存可以设置返回的缓存对象策略: <cache readOnly="true">。当readOnly="true"时,表示二级缓存返回给所有调用者同一个缓存对象实例,调用者可以 update 获取的缓存实例,但是这样可能会造成其他调用者出现数据不一致的情况(因为所有调用者调用的是同一个实例)。当 readOnly="false"时,返回给调用者的是二级缓存总缓存对象的拷贝,即不同调用者获取的是缓存对象不同的实例,这样调用者对各自的缓存对象的修改不会影响到其他的调用者,即是安全的,所以默认是 readOnly="false";
③ 对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存 Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
6: 拦截器和过滤器有哪些区别?
* 拦截器是基于 java 的反射机制的,而过滤器是基于函数回调
* 拦截器不依赖与 servlet 容器,而过滤器依赖与 servlet 容器
* 拦截器只能对 action 请求起作用,而过滤器则可以对几乎所有的请求起作用
* 拦截器可以访问 action 上下文、值栈里的对象,而过滤器不能
* 在 action 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一 次 .
7: 简单介绍一下 zookeeper 以及 zookeeper 的原理 ?
session:
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper 的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、 功能稳定的系统提供给用户。
ZooKeeper 包含一个简单的原语集, 提供 Java 和 C 的接口。
ZooKeeper 代码版本中,提供了分布式独享锁、选举、队列的接口,代码在 zookeeper-3.4.3\src\recipes。其中分布锁和队列有 Java 和 C 两个版本,选举只有 Java 版本。
原理:
ZooKeeper 是以 Fast Paxos 算法为基础的,Paxos 算法存在活锁的问题,即当有多个 proposer 交错提交时,有可能互相排斥导致没有一个 proposer 能提交成功,而 Fast Paxos 作了一些优化,通过选举产生一个 leader (领导者),只有 leader 才能提交 proposer,具体 算法可见 Fast Paxos。因此,要想弄懂 ZooKeeper 首先得对 Fast
Paxos 有所了解。
ZooKeeper 的基本运转流程:1、选举 Leader。 2、同步数据。 3、选举 Leader 过程中算法有很多,但要达到的选举标准是一致的。 4、 Leader 要具有最高的执行 ID,类似 root 权限。 5、集群中大多数的机器得到响应并 follow 选出的 Leader。
扩展阅读