34、Java中的关键字 transient
Java中transient关键字的作用,简单地说,就是让某些被修饰的成员属性变量不被序列化
35、Reader与InputStream两个类中的read()的区别
InputStream类的read()方法是从流里面取出一个字节,他的函数原型是 int read(); Reader类的read()方法则是从流里面取出一个字符(一个char),他的函数原型也是 int read();
36、Java Integer的缓存策略
package com.javapapers.java; public class JavaIntegerCache { public static void main(String... strings) { Integer integer1 = 3; Integer integer2 = 3; if (integer1 == integer2) System.out.println("integer1 == integer2"); else System.out.println("integer1 != integer2"); Integer integer3 = 300; Integer integer4 = 300; if (integer3 == integer4) System.out.println("integer3 == integer4"); else System.out.println("integer3 != integer4"); } }
大多数人都认为上面的两个判断的结果都是 false。虽然它们的值相等,但由于比较的是对象,而对象的引用不一样,所以会认为两个 if 判断都是 false 的。在 Java 中,== 比较的是对象引用,而 equals 比较的是值。因此,在这个例子中,不同的对象有不同的引用,所以在进行比较的时候都应该返回 false。但是奇怪的是,这里两个相似的 if 条件判断却返回不同的布尔值。
下面是上面代码真正的输出结果,
integer1 == integer2
integer3 != integer4
Java 中 Integer 缓存实现
在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。
上面的规则适用于整数区间 -128 到 +127。
37.反射能获取到父类的私有方法吗?怎么防止反射破坏单例模式
单例模式一般构造方法都是private,目的就是为了防止外界调用私有构造器创建多个实例
但是反射能够访问私有的构造方法,只要反射获取的构造器调用setAccessible(true)方法即可。这样调用一次就会产生一个实例,调用多次就时多个实例,从而破坏单例。
只要在单例的私有构造器中添加判断单例是否已经构造的代码,如果单例之前已经构造,则抛出异常,如果没有构造,则无所谓。
还有一种就是枚举单例,枚举单例没有构造函数无法通过反射来攻击。
38.拦截器与过滤器的区别
- 拦截器是基于java的反射机制的,而过滤器是基本函数回调。
- 拦截器不依赖于servlet容器,过滤器依赖于servlet容器
- 拦截器只能对action请求起作用,过滤器可以对几乎所有的请求起作用
- 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问
- 在action的生命周期中,拦截器可以被多次调用,而过滤器只能在容器初始化时被调用过一次。
JVM 知识
1. 什么情况下会发生栈内存溢出。
至于是堆内存溢出还是方法区内存溢出还是栈内存溢出,其实可以用一些工具比如 JConsole来监视
2. JVM 的内存结构,Eden 和 Survivor 比例。
3. jvm 中一次完整的 GC 流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的 jvm 参数。
4. 你知道哪几种垃圾收集器,各自的优缺点,重点讲下 cms,包括原理,流程,优缺点
5. 垃圾回收算法的实现原理。
6. 当出现了内存溢出,你怎么排错。
内存溢出分析 JAVA dump查看线程运行情况: =====查看栈信息======================= 1.查询java程序pid netstat -ntpl | grep 8080 2.使用jstack [-l] 进程pid > xxx.log将进程里所有线程信息输入到指定文件中 1)如果程序正常运行:使用jstack [-l] 进程pid > xxx.log将所有线程信息输入到指定文件中 2)如果程序无响应:使用 jstack -F [-m] [-l] 进程pid >xxx.log强制打印栈信息 =====查看堆信息======================= 3.使用top命令找出占用cpu高(或者执行时间很长)的进程pid 4.使用top -H -p 线程pid 找出占用cpu高(或执行时间长)的线程pid 5.将占用cpu高的线程pid转换成16进制(window自带计算器) 6.dump该进程的内存 jmap -dump:format=b,file=文件名 [进程pid] 将转换后的pid在开始输出的dump文件(xxx.log)中搜索对应线程信息 7.eclipse Memory Analyzer 对dump文件分析
7. JVM 内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。
volatile关键字禁止指令重排序(内存栅栏)有两层意思 1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对 后面的操作可见;在其后面的操作肯定还没有进行; 2)在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语 句放到其前面执行。 Happen-Before 原则 1. 程序次序原则:一个线程内,按照程序代码顺序,书写在前面的操作先发生于书写在后面的操作。 2. volatile 规则:volatile 变量的写,先发生于读,这保证了 volatile 变量的可见性。 3. 锁规则:解锁(unlock) 必然发生在随后的加锁(lock)前。 4. 传递性:A先于B,B先于C,那么A必然先于C。 5. 线程的 start 方法先于他的每一个动作。 6. 线程的所有操作先于线程的终结。 7. 线程的中断(interrupt())先于被中断的代码。 8. 对象的构造函数,结束先于 finalize 方法。
并发编程之 Java 内存模型 + volatile 关键字 + Happen-Before 规则_击水三千里的专栏-CSDN博客
8. 简单说说你了解的类加载器。
JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize) 链接又分为三个步骤 验证:确保被加载类的正确性; 准备:为类的静态变量分配内存,并将其初始化为默认值; 解析:把类中的符号引用转换为直接引用; 加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一 次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。 1)Bootstrap ClassLoader 负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类 2)Extension ClassLoader 负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下 的jar包 3)App ClassLoader 负责记载classpath中指定的jar包及目录中class 4)Custom ClassLoader 属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader
9.spring里创建出来对象的存活时间
目前的系统,大部分是spring容器的对象,spring默认单实例方式加载,这些对象可能会存在老年代中。
但是方法内部new出来的对象不会存活太长时间,方法结束,引用消息,对象也会在下一次gc被回收。
10. 你们线上应用的 JVM 参数有哪些。
-Xms512m -Xmx512m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -Xmn256m -XX:MaxDirectMemorySize=1g -XX:SurvivorRatio=10 -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=5000 ##垃圾回收会清理持久代,移除不再使用的classes,只有在 UseConcMarkSweepGC 也启用的情况下才有用 -XX:+CMSClassUnloadingEnabled ##使用cms作为垃圾回收使用80%后开始CMS收集 -XX:CMSInitiatingOccupancyFraction=80 ##使用手动定义初始化定义开始CMS收集 -XX:+UseCMSInitiatingOccupancyOnly ##使用并发的方式执行FGC -XX:+ExplicitGCInvokesConcurrent ## 设置并行垃圾回收的线程数。此值可以设置与机器处理器数量相等 -XX:ParallelGCThreads=4 -Xloggc:$work_dir/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$work_dir/logs/java.hprof
11. g1 和 cms 区别,吞吐量优先和响应优先的垃圾收集器选择。
Cms是以获取最短回收停顿时间为目标的收集器。基于标记-清除算法实现。比较占用cpu资源,切易造成碎片。 G1是面向服务端的垃圾收集器,是jdk9默认的收集器,基于标记-整理算法实现。可利用多核、多cpu,保留分 代,实现可预测停顿,可控。
12. 请解释如下 jvm 参数的含义:
-server -Xms512m -Xmx512m -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxTenuringThreshold=20 -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly。 ##设置JVM最大可用内存为3550M。 -Xmx3550m #设置JVM初始内存为3550m,可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。 -Xms3550m #设置每个线程的堆栈大小。在相同物理内 存下,减小这个值能生成更多的线程。但是操作系统对一 #个进程内的线程数还是有限制的,不能无限生成, #经验值在3000~5000左右 -Xss128k #设置持久代大小为16m -XX:MaxPermSize=16m #设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直 #接进入年老代。对于年老代比较多的应用,可以提高效率。 #如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 #时间,增加在年轻代即被回收的概论。 -XX:MaxTenuringThreshold=0
系统学习JVM知识这篇文章讲的比较清楚
问题和实战
开源框架知识
1. 简单讲讲 tomcat 结构,以及其类加载器流程。
tomcat结构
Tomcat的核心组件就Connector和Container,一个Connector+一个Container(Engine)构成一个Service,Service就是对外提供服务的组件,有了Service组件Tomcat就能对外提供服务了,但是光有服务还不行,还需要有环境让你提供服务才行,所以最外层的Server就是为Service提供了生存的土壤。
Container 是容器的父接口,所有子容器都必须实现这个接口,Container 容器的设计用的是典型的责任链的设计模式,它有四个子容器组件构成,分别是:Engine、Host、Context、Wrapper,这四个组件不是平 行的,而是父子关系,Engine 包含 Host,Host 包含 Context,Context 包含 Wrapper。通常一个 Servlet class 对应一个 Wrapper,如果有多个 Servlet 就可以定义多个 Wrapper,如果有多个 Wrapper 就要定义一个更高的 Container 了
在Tomcat 6中默认情况下,Jar包的加载顺序是:
1)JRE中的Java基础包 2)Web应用WEB-INF\lib下的包 3)Tomcat\lib下的包
线程模型:支持以下四种线程模型。
3. 讲讲 Spring 加载流程。
4. 讲讲 Spring 事务的传播属性。
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
5. Spring 如何管理事务的。
6. Spring 怎么配置事务(具体说出一些关键的 xml元素)。
tx:advice,aop:config
7. 说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理,aop 的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的。
8. SpringMVC 中 DispatcherServlet初始化过程。
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获; 2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回; 3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法) 4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作: HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中 5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象; 6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ; 7. ViewResolver 结合Model和View,来渲染视图
9.SpringBoot主要解决了什么问题
1. 创建独立的 Spring 应用程序
2. 嵌入的 Tomcat,无需部署 WAR 文件
3. 简化 Maven 配置
4. 自动配置 Spring
5. 供生产就绪型功能,如指标,健康检查和外部配置
6. 自定义代码配置代替XML
操作系统
1. Linux 系统下你关注过哪些内核参数,说说你知道的。
2. Linux 下 IO 模型有几种,各自的含义是什么。
1.BIO(blocking IO):同步阻塞 I/O 2.NIO(nonblocking IO):同步非阻塞 I/O 3.多路复用IO( IO multiplexing) 4.信号驱动I/O( signal driven IO) 5.异步 I/O(asynchronous IO)
【Linux基础】Linux的5种IO模型详解_白夜行-CSDN博客_基本io模型
3. epoll 和 poll 有什么区别。
select、poll、epoll都是IO多路复用的机制,先是监听多个文件描述符FD,一旦某个FD就绪,就可以进行相应
的读写操作。但是select、poll、epoll本质都是同步I/O,他们都需要在读写事件就绪之后自己负责读写,即这个读写过程是阻塞的
总结:
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。
4. 平时用到哪些 Linux 命令。
递归计算当前目录的文件,包括隐藏文件。
# find . -type f | wc -l
语法:
find
: 搜索目录结构中的文件
-type
: 文件类型
f
: 常规文件
-l
: 输出换行符的数量wc [选项] 文件 :该命令统计给定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也给出所有指定文件的总统计数。字是由空格字符区分开的最大字符串。
该命令各选项含义如下
- c 统计字节数。
- l 统计行数。
- w 统计字数。
$ wc - lcw file1 file2
4 33 file1
7 52 file2
11 11 85 total
批量替换文本内容
sed -i 's/^Str/String/' replace.txt 把每行第一个Str替换为String
sed -i 's/^Str/String/g' replace.txt 把Str全文替换为String
sed -i 's/\.$/\;/' replace.txt 把.结尾替换为;
sed -i 's/^ *$/d' replace.txt 删除文本中的空行
sed -i 's/Integer/d' replace.txt 删除Integer所在行
检索文件内容常用指令
'
5. 用一行命令查看文件的最后五行。
输出test文件的后五行: liyi@liyi:~/Desktop > tail -n 5 test 输出test文件的前五行: liyi@liyi:~/Desktop > head -n 5 test
6. 用一行命令输出正在运行的 java 进程。
jps
7. 介绍下你理解的操作系统中线程切换过程。
线程的切换只有指令的切换,同处于一个进程里面,不存在映射表的切换。进程的切换就是在线程切换的基础上加上映射表的切换。
8. 进程和线程的区别。
9.用户态和内核态是什么?
内核态: CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序
用户态: 只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取
10.怎么批量替换一个文件夹下所有文件中的一个字符?
sed -i "s/oldString/newString/g" `grep oldString -rl /path`
多线程
1. 多线程的几种实现方式,什么是线程安全。
2. volatile 的原理,作用,能代替锁么。
3. 画一个线程的生命周期状态图。
4. sleep 和 wait 的区别。
5. Lock 与 Synchronized 的区别。
总结来说,Lock和synchronized有以下几点不同: 1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现; 2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异 常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放 锁; 3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直 等待下去,不能够响应中断; 4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。 5)Lock可以提高多个线程进行读操作的效率。 在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时 竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
6. synchronized 的原理是什么,解释以下名词:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。
synchronized 的原理
monitor对象存在于每个Java对象的对象头中(存储的指针的指向),synchronized锁便是通过这种方式获取锁的
偏向锁
大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引人了偏向锁
轻量级锁
如果没有竞争,轻量级锁使用CAS操作,避免使用互斥量
如果存在竞争,除了互斥量的开销,还有 CAS的操作,不仅没有提升,反而性能会下降
重量级锁
重量级锁,使用的是系统互斥量实现的
7. 用过哪些原子类,他们的原理是什么。
8. 用过线程池吗,newCache 和 newFixed 有什么区别,他们的原理简单概括下,构造函数的各个参数的含义是什么,比如 coreSize,maxsize 等。
Executors.newCachedThreadPool():无限线程池。 Executors.newFixedThreadPool(nThreads):创建固定大小的线程池。 Executors.newSingleThreadExecutor():创建单个线程的线程池。 1.ExecutorService threadPool = Executors.newCachedThreadPool(); SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移 除操作take。所以newCachedThreadPool实际项目一般也很少运用 2.ExecutorService executor = Executors.newFixedThreadPool(3); 这个线程池的队列LinkedBlockingQueue没有指定默认大小,高并发环境下 在对内存压力很大,所以生产环境一般都不使用这个
9. 线程池的关闭方式有几种,各自的区别是什么。
shutdown() 执行后停止接受新任务,会把队列的任务执行完毕。 shutdownNow() 也是停止接受新任务,但会中断所有的任务,将线程池状态变为 stop。
详细介绍见:讲解线程池的一篇干货,很干很干!
10. 假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多有 10 个线程同时调用它,如何做到。
基于redis分布式限流超时时间设为1s
详细介绍见:单机限流和分布式应用限流_击水三千里的专栏-CSDN博客_分布式限流和单机限流
11. spring 的 controller 是单例还是多例,怎么保证并发的安全。
singleton : bean在每个Spring ioc 容器中只有一个实例。 prototype:一个bean的定义可以有多个实例。 request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。