集合相关:
1、HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
2、HashMap和Hashtable的区别。
Hashtable方法是同步的 HashMap方法是非同步的 Hashtable基于Dictionary类 HashMap基于AbstractMap,而AbstractMap基于Map接口的实现 Hashtable中key和value都不允许为null,遇到null,直接返回NullPointerException HashMap中key和value都允许为null,遇到key为null的时候,调用putForNullKey方法进行处理,而对value没有处理 Hashtable中hash数组默认大小是11,扩充方式是old*2+1 HashMap中hash数组的默认大小是16,而且一定是2的指数
3、ArrayList、LinkedList、Vector的区别。
LinkedList底层是双向链表 ArrayList底层是可变数组 LinkedList不允许随机访问,即查询效率低 ArrayList允许随机访问,即查询效率高 LinkedList插入和删除效率快 ArrayList插入和删除效率低 Vector同步、线程安全的 ArrayList异步、线程不安全 Vector 需要额外开销来维持同步锁,性能慢 ArrayList 性能快 Vector 可以使用Iterator、foreach、Enumeration输出 ArrayList 只能使用Iterator、foreach输出
4、HashMap和ConcurrentHashMap的区别。
5、HashMap和LinkedHashMap的区别。
LinkedHashMap有序的,有插入顺序和访问顺序 HashMap无序的 LinkedHashMap内部维护着一个运行于所有条目的双向链表 HashMap内部维护着一个单链表
6、HashMap是线程安全的吗。
不是线程安全的
7、ConcurrentHashMap是怎么实现线程安全的。
多线程并发相关问题:
1、创建线程的3种方式。
继承Thread类创建线程类 通过Runnable接口创建线程类 通过Callable和Future创建线程
2、什么是线程安全。
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
3、Runnable接口和Callable接口的区别。
Callable接口有返回值,Runnable接口没有返回值。 Callable接口call()方法抛异常,Runnable接口run()方法不抛异常 Callable接口实现方法是call()方法,Runnable接口实现方法是run()方法。
4、wait方法和sleep方法的区别。
sleep是Thread的静态方法,wait是Object的方法,任何对象实例都能调用。 sleep不会释放锁,它也不需要占用锁。wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)。 它们都可以被interrupted方法中断。
5、synchronized、Lock、ReentrantLock、ReadWriteLock。
Java多线程——锁(Synchronized、Lock、ReentrantLock、ReadWriteLock、ReentrantReadWriteLock)
6、介绍下CAS(无锁技术)。
7、volatile关键字的作用和原理。
系统对volatile变量进行操作的时候JVM想处理器发送一条带lock前缀的指令,处理器在接受到lock指令时,会立马将缓存中的数据写回到内存中,并且这个操作过程会采用缓存一致性原则,也叫缓存锁定,来保证修改过程的原子性,他会禁止同时操作两个以上的缓存对应的内存区域的数据。 数据写回之后,其他的处理器里面的缓存这个时候还没有变,但是各个处理器会一直在系统总线上嗅探数据,一旦发现自己的缓存行对应的内存地址被修改,就会把处理器的缓存行设置为,无效状态,当处理器又访问到无效状态的缓存时,会被强制要求从对应的内存中拿最新的数据。
8、什么是ThreadLocal。
ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
9、ThreadPoolExecutor的内部工作原理。
ThreadPoolExecutor的内部工作原理,整体思路总结为5句话:
如果线程池大小poolSize小于corePoolSize,则创建新线程执行任务。 如果线程池大小poolSize大于corePoolSize,且等待队列未满,则进入等待队列。 如果线程池大小poolSize大于corePoolSize且小于maximumPoolSize,且等待队列已满,则创建新线程执行任务。 如果线程池大小poolSize大于corePoolSize且大于maximumPoolSize,且等待队列已满,则调用拒绝策略来处理该任务。 线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在keepAliveTime里等不到新的任务了,那么线程就会退出。 ThreadPoolExecutor线程池中拒绝策略:
AbortPolicy:为java线程池默认的阻塞策略,不执行此任务,而且会直接抛出一个执行时异常,切记TreadPoolExecutor.execute需要try catch,否则程序会直接退出。 DiscardPolicy:直接抛弃,任务不执行,空方法 DiscardOldestPolicy:从队列里面抛弃head的一个任务,并再次execute 此任务(task) CallerRunsPolicy:在调用execute的线程里面执行此command,会阻塞入口。 用户自定义拒绝策略:实现RejectdExecutionHandler,并自己定义策略模式。
10、分布式环境下,怎么保证线程安全。
避免并发 在分布式环境中,如果存在并发问题,那么很难通过技术去解决,或者解决的代价很大,所以我们首先要想想是不是可以通过某些策略和业务设计来避免并发。比如通过合理的时间调度,避开共享资源的存取冲突。另外,在并行任务设计上可以通过适当的策略,保证任务与任务之间不存在共享资源,比如在以前博文中提到的例子,我们需要用多线程或分布式集群来计算一堆客户的相关统计值,由于客户的统计值是共享数据,因此会有并发潜在可能。但从业务上我们可以分析出客户与客户之间 数据是不共享的,因此可以设计一个规则来保证一个客户的计算工作和数据访问只会被一个线程或一台工作机完成,而不是把一个客户的计算工作分配给多个线程去 完成。这种规则很容易设计,例如可以采用hash算法。
时间戳 分布式环境中并发是没法保证时序的,无论是通过远程接口的同步调用或异步消息,因此很容易造成某些对时序性有要求的业务在高并发时产生错误。比如系统A需要把某个值的变更同步到系统B,由于通知的时序问题会导致一个过期的值覆盖了有效值。对于这个问题,常用的办法就是采用时间戳的方式,每次系统A发送变更给系统B的时候需要带上一个能标示时序的时间戳,系统B接到通知后会拿时间戳与存在的时间戳比较,只有当通知的时间戳大于存在的时间戳,才做更新。这种方式比较简单,但关键在于调用方一般要保证时间戳的时序有效性。
串行化 有的时候可以通过串行化可能产生并发问题操作,牺牲性能和扩展性,来满足对数据一致性的要求。比如分布式消息系统就没法保证消息的有序性,但可以通过变分布式消息系统为单一系统就可以保证消息的有序性了。另外,当接收方没法处理调用有序性,可以通过一个队列先把调用信息缓存起来,然后再串行地处理这些调用。
数据库 分布式环境中的共享资源不能通过Java里同步方法或加锁来保证线程安全,但数据库是分布式各服务器的共享点,可以通过数据库的高可靠一致性机制来满足需求。比如,可以通过唯一性索引来解决并发过程中重复数据的生产或重复任务的执行;另外有些更新计算操作也尽量通过sql来完成,因为在程序段计算好后再去更新就有可能发生脏复写问题,但通过一条sql来完成计算和更新就可以通过数据库的锁机制来保证update操作的一致性。
行锁 有的事务比较复杂,无法通过一条sql解决问题,并且有存在并发问题,这时就需要通过行锁来解决,一般行锁可以通过以下方式来实现: 对于Oracle数据库,可以采用select ... for update方式。这种方式会有潜在的危险,就是如果没有commit就会造成这行数据被锁住,其他有涉及到这行数据的任务都会被挂起,应该谨慎使用 在表里添加一个标示锁的字段,每次操作前,先通过update这个锁字段来完成类似竞争锁的操作,操作完成后在update锁字段复位,标示已归还锁。这种方式比较安全,不好的地方在于这些update锁字段的操作就是额外的性能消耗
统一触发途径 当一个数据可能会被多个触发点或多个业务涉及到,就有并发问题产生的隐患,因此可以通过前期架构和业务设计,尽量统一触发途径,触发途径少了一是减少并发的可能,也有利于对于并发问题的分析和判断。
框架:
1、Hibernate和Mybatis的区别。
Hibernate 具有良好的管理机制,用户不需要关注SQL,如果二级缓存出现脏数据,系统会保存,;
Mybatis 在使用的时候要谨慎,避免缓存CAche 的使用。
2、Spring MVC和Struts2的区别。
3、Spring用了哪些设计模式。
4、Spring中AOP主要用来做什么。
5、Spring注入bean的方式。
Set()注入 构造器注入 静态工厂的方法注入 实例工厂的方法注入
6、什么是IOC,什么是依赖注入。
什么是控制反转(IoC)?什么是依赖注入(DI)?以及实现原理
7、Spring是单例还是多例,怎么修改。
8、Spring事务隔离级别和传播性。
9、介绍下Mybatis/Hibernate的缓存机制。
10、Mybatis的mapper文件中#和$的区别。
关键字作为参数,使用"$",两边不加""。 非关键字作为参数,使用"#"防注入。 其他情况优先使用"#"
11、Mybatis的mapper文件中resultType和resultMap的区别。
resultMap 是在 mapper.xml 文件中通过 resultMap 节点定义出来的 returnType 是 自定义 JavaBean、使用 mybatis 内置 或 jdk 自带的类型、容器。
其他问题:
1、介绍下栈和队列。
2、IO和NIO的区别。
3、接口和抽象类的区别。
相同点: 都不能被实例化 接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。
不同点: 接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。 实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。 接口强调特定功能的实现,而抽象类强调所属关系。 接口成员变量默认为public static final,必须赋初值,不能被修改;其所有的成员方法都是public、abstract的。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。 接口被用于常用的功能,便于日后维护和添加删除,而抽象类更倾向于充当公共类的角色,不适用于日后重新对立面的代码修改。功能需要累积时用抽象类,不需要累积时用接口。
4、int和Integer的自动拆箱/装箱相关问题。
常量池相关问题。 1、==和equals的区别。
“==”是运算符 如果比较的对象是基本数据类型,则比较的是其存储的值是否相等; 如果比较的是引用数据类型,则比较的是所指向对象的地址值是否相等(是否是同一个对象)
equals是Object的方法,用来比较两个对象的内容是否相等。 equals 方法不能用于比较基本数据类型,如果没有对 equals 方法进行重写,则相当于“==”,比较的是引用类型的变 量所指向的对象的地址值。 一般情况下,类会重写equals方法用来比较两个对象的内容是否相等。比如String类中的equals()是被重写了,比较的是对象的值。
2、重载和重写的区别。
重载 (Overloading) 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数 / 类型。 重载 Overloading 是一个类中多态性的一种表现。 Java 的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法 , 这就是多态性。 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。 无法以 返回型别 作为重载函数的区分标准。
重写(Overriding) 父类与子类之间的多态性,对父类的函数进行重新定义。 如果在子类中定义某 方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding) 。 在 Java 中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。 若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表, 则新方法将覆盖原有的方法。 如需父类中原有的方法,可使用 super 关键字,该关键字引用了当前类的父类。 子类函数的访问修饰权限不能少于父类的;
3、String和StringBuilder、StringBuffer的区别。
String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全)
4、静态变量、实例变量、局部变量线程安全吗,为什么。
静态变量:线程不安全 静态变量位于方法区,为所有对象共享,它们共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程不安全。
实例变量:单例模式或只对一个对象进行操作时线程不安全 实例变量为对象实例私有,在虚拟机堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,犹如静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程不安全; 如果每个线程都是在不同的对象中,那么对象与对象之间的实例变量的修改将互不影响,故线程安全。
局部变量:线程安全 每个线程执行时将会把局部变量放在各自栈的工作内存中,线程间不共享,故不存在线程安全问题。
5、try、catch、finally都有return语句时执行哪个。
任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。 如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的, 编译器把finally中的return实现为一个warning。
6、介绍下B树、二叉树。
二叉树,平衡二叉树,红黑树,b树,b+树,b*树的缺点与优点以及使用场景
7、ajax的4个字母分别是什么意思。
Asynchronous JavaScript and XML 的缩写,异步的JavaScript和XML。在不重新加载整个页面的情况下 ,AJAX 与服务器交换数据并更新部分网页。
8、object中有哪些方法。