Java面试题
- int 和Integer有什么区别
如果整型字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象。 - 为什么要用SpringBoot?
- 因为Java EE使用Spring逐渐变得笨重起来,大量的XML文件存在与项目中,繁琐的配置,整合第三方框架的配置问题,低下的开发效率和部署效率等等问题
- 遵循“习惯优于配置”的原则,使用Spring Boot只需要很少的配置,大部分的时候我们直接使用默认的配置即可
- 项目快速搭建,可以无需配置的自动整合第三方的框架
- 可以完全不使用XML配置文件,只需要自动配置和Java Config
- 内嵌Servlet容器,降低了对环境的要求,可以使用命令直接执行项目,应用可用jar包执行:java -jar
- Spring的核心功能是什么?
- DI(依赖注入):在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。
- IOC(控制反转):和依赖注入思想一样,通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做。
- AOP(面向切面编程):AOP实现的目标是 把横切关注点从业务逻辑中分离,独立模块化。在不改变现有代码的前提下,动态的添加功能。
Spring核心功能
- AOP如何去实现?
AOP实现原理 - jdk代理和cgLib代理的区别
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。 - 线程的状态
- 新建(new):新创建了一个线程对象。
- 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权。
- 运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
- 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
- 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
- 运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
- 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
- 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
- ConcurrentHashMap的实现原理
Jsp九大内置对象及四个作用域
http://www.blogjava.net/ourday/archive/2008/09/20/230107.html
- Cookie与Session的区别
数据库
- 数据库事务的四大特性是什么
- 原子性(atomicity):一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全- 部提交成功,要么全部失败回滚,对于一个事务来说,不可以只执行其中的一部分操作。
- 一致性(consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。
- 隔离性(isolation):通常来说,一个事务所做的修改在最终提交之前,对其他事务是不可见的。
- 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。
- 事务的隔离级别
- 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
- 提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
- 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读
- 串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
事务的隔离级别
- 乐观锁和悲观锁
- 悲观锁
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被block。 - 乐观锁
乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
乐观锁一般来说有以下2种方式:
- 使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。
使用时间戳(timestamp)。 - 乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
Java JUC中的atomic包就是乐观锁的一种实现,AtomicInteger 通过CAS(Compare And Set)操作实现线程安全的自增。
- 使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。
- 悲观锁
- 数据库索引的原理
左右连接、内连接区别
http://www.cnblogs.com/youzhangjin/archive/2009/05/22/1486982.html- -
计算机网络
数据结构
- 几种排序算法的时间复杂度和空间复杂度和算法思想
- 树的非递归遍历
- 哪两种遍历方式不能确定一颗树
- 二叉平衡树
- 堆的动态调整
- 迪杰斯特拉算法
Linux
- 日志查看命令
日志查看命令详解
操作系统
自旋锁
何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。
自旋锁进程、线程与处理器的调度
http://www.cnblogs.com/gaopeng527/p/5260897.htmlcpu load
http://www.ruanyifeng.com/blog/2011/07/linux_load_average_explained.html死锁是什么,怎么避免死锁
http://blog.csdn.net/abigale1011/article/details/6450845线程的好处?
线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源,又可以独立调度,更加轻量级。