HashMap: 不是线程安全的,键和值都可以为空,没有锁机制。
HashTable: 给整张表加锁,键和值都不能为空,采用synchronized关键字
HashMap为什么不是线程安全的?
HashMap没有锁机制,在HashMap内部加锁会增加单线程访问的资源消耗,即使没有多线程访问,也要每次检查加锁解锁。
线程不安全主要体现在两个线程同时操作put()方法,后面的值会覆盖前面的值,多线程环境下,使用HashMap进行put()操作会引起死循环,导致CPU的使用率接近100%.
如果多个线程同时检测到元素个数超过数组大小需要扩容,多个线程操作数组扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容成功,其他的线程都会丢失,各自put的数据也会丢失。
HashMap基于 哈希原理,我们使用 Put() 存储对象到 HashMap中,使用 get() 中获取对象。当我们给 put() 方法传递键值时,先对键调用 hashCode() 方法,返回的 hashCode用于找到 bucket 桶的位置来存储 Entry 对象,Entry中存储的是对象,键值对,如果 hashCode 相同,则先通过 hashCode 找到对应的 bucket,再通过 keys.value()找到正确节点。
哈希表:哈希表是一种数据结构,结合了数组和链表,一个长度为 16 的数组,每一个元素存储链表的头结点。
线程池参数:
corePollSize: 核心线程数,在创建了线程池之后,线程中没有任何线程,等到有任务来时才会创建线程去执行任务,默认情况下,创建了线程池后,线程数为0,当有任务到来时才创建线程去执行任务。
naxinumPoolSize: 最大线程数
keepAliveTime: 空闲线程的保留时间
ThreadFactory: 线程工厂,用来创建线程
BlockingQueue<Runnable>: 阻塞队列,存储等待执行的任务。
ConcurrentHashMap: JDK1.5中提供的 Concurrent 包,用到了分段锁的概念,将一个大 MAp分成 n个小的 HashTable, 将 Map分成了 n个 Segment,默认16个桶,效率提升 N倍,默认效率提升 16 倍。
使用 lock()做同步,键值不允许有 null.。
Spring的常用注解:
@Component 注解声明这是一个 bean 对象
@Autowired 注解声明此处需要一个 bean 类型的对象装配注入
@Service 对于业务逻辑层进行注解
@Controllor 对于控制层进行注解
@ Repository 对于 dao层进行注解
1. java 为什么子类不能继承父类的构造方法?
构造方法的作用是初始化类u,子类初始化子类,父类初始化父类,在子类调用自己的构造方法前,会先自动调用父类的无参构造方法,先生成父类对象,再生成子类对象。如果父类没有无参的构造方法,子类就必须用 super()显示调用父类的构造方法,先有父亲才会有孩子。
2. 关于类型的强转与 instanceof运算符:
进行强制类型转换的时候,有可能会出现异常,无法强制转换,于是为了代码更加健壮,在强转之前,用 instanceof运算符进行判断。
eg:
if(objPri instanceof String) {
String str = (String)objPri;
}
instanceof判断 objPri 是否属于 String,即判断 objPri 是否是 String 类型的一个实例,是的话返回 true,不是的话返回 false;从而保证类型强转的时候不会失败,提高健壮性。
继承和组合:
继承是对父类进行改造,获得一个特殊的版本,应对实际使用,子类可以改变父类的类和方法,这样耦合性太强。
组合则是将很多个父类组合起来,降低耦合性。
需要注意的是,组合和继承两者的开销并不会差很多,分配的内存空间也不会差太多。
初始化块:
一个类中可以有多个初始化块,先定义的先执行,后定义的后执行。
初始化块的修饰符只能是 static,使用 static 修饰的初始化块被称为静态初始化块。
加上static 关键字,就表示是一个静态初始化块,也被称为类初始化块,普通初始化块负责在对象执行的时候初始化,static初始化块负责对类进行初始化。因此,静态初始化块比普通初始化块先执行。
静态初始化块和普通初始化块不同,普通初始化块在 javac 编译后会消失,会被还原到构造器中,但是 static 不会消失,因为它是类构造器,不是对象构造器。所以所有的静态初始化块都会最先执行。
AOP : 横切性的关注点,是一种独立的服务,遍布在系统的各个角落,将这个类进行模块化(Aspect)操作,只是在方法上执行一些advice 操作,分为before advice, after advice 或者 Throw advice.
动态代理,会有延迟和时间的消耗。
Spring对象的作用域(scope):
(1)默认情况下,只返回一个 bean, 也就是 singleton
(2)prototype,每次调用 getBean()向IOC取得的对象是不一样的,最好将这种实例创建成无状态的
(3)提供了AOP声明式服务能力,可以针对 POJO 对象提供声明式服务能力,如:声明式事务
(4)对于资源,如 Hibernate Session或者 JDBC Connection 我们不负责开启和关闭。
HashMap, HashTable, ConcurrentHashMap的区别:
HashTable:底层数组+链表实现, 无论 key还是 value 都不能是 null, 线程安全。实现线程安全的方式是在修改数据的时候锁住整个HashTable,效率低,ConcurrentHashMap做了优化。
HashMap:底层数组+链表实现,可以存储null键和 null 值,线程不安全,扩容针对整个 map, 每次扩容的时候,原来数组的元素依次重新计算存放位置,并重新插入。
ConcurrentHashMap: 底层采用分段的数组+链表实现,线程安全,把整个 Map分成 n个 Segment, 默认 16个桶,提供相同的线程安全,效率提升,读操作不加锁(HashEntry的value变量是 volatile 的,可以保证原子性)
扩容是段内扩容,不对整张表进行扩容。
wait()和 sleep()的区别:
sleep没有释放锁,wait()方法释放锁,wait(), notify(), notifyAll()三个只能在同步方法或者同步控制块中使用,sleep可以在任何地方使用。
wait() 方法基于 Object,sleep()方法基于 Thread类
sleep必须捕获异常,被其他线程调用interrupt(),会抛出interruptedException异常,而 wait()不需要,
object类有哪些方法:
wait(),notify(),notifyAll(),toString(),equals(),finalize()进行垃圾回收之前会用到
clone()克隆出另外一个当前已经存在的对象 , hashCode()。
Spring中ApplicationContext和BeanFactory的区别,以及 Spring bean 的作用域:
ApplicationContext和BeanFactory 都是 spring容器,BeanFactory是Spring中比较古老的 Factory, 所以无法支持 Spring 插件,如 AOP,web等功能。
ApplicationContext是 BeanFactory的子类,ApplicationContext基本替代了 BeanFactory的功能,以一种更面向框架的工作方式对上下文进行分层并且实现继承,并提供了一些其他的功能。ApplicationContext在加载配置文件的时候会创建所有的bean,好处是预先加载,坏处是浪费内存。
BeanFactory:加载配置文件的时候不会创建所有的bean, 而是等到使用的时候才会创建,好处是节约内存坏处是速度慢。
没有特殊要求的情况下,要使用ApplicationContext,因为 BeanFactory能完成的事情,ApplicationContext都可以完成,并且提供了更多接近现在开发的功能。
SpringBean的创建是典型的工厂模式,最底层的接口是 BeanFactory, ApplicationContext是 BeanFactory的一个高富帅实现,是 Spring 提供的一个高级 IOC容器,除了能够提供 IOC容器的基本功能之外,还为用户提供了其他附加服务,如支持信息源,可以实现国际化,访问资源和支持应用事件。
SpringBean的作用域:
singleton 单例模式,全局只有一个实例
prototype 每次调用产生一个新的实例
request: 每次请求产生一个 bean,在 webApplicationContext 中用
session: 每个用户 session产生一个新的 bean, 不同用户之间的 bean互相不影响,在webApplicationContext 中用
global-session: 作用和 session 类似,多个 session 中可以共享,在 webApplicationContext中用。