1 String、StringBuffer、Stringbuilder有什么区别
String是一个不可变类(一个String对象创建之后,直到这个对象销毁为止,对象中的字符序列都不能被改变)。
StringBuffer对象则代表一个字符序列可变的字符串(当一个StringBuffer对象被创建之后,我们可以通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()、等方法来改变这个字符串对象的字符序列)。
当通过StringBuffer得到期待中字符序列的字符串时,就可以通过toString()方法将其转换为String对象。
与StringBuffer类相比,它们有共同的父类`AbstractStringBuilder`,二者无论是构造器还是方法都基本相同,不同的一点是,StringBuilder没有考虑线程安全问题,也正因如此,StringBuilder比StringBuffer性能略高。
String | StringBuffer | StringBuilder |
线程安全。 原因:value数组是final类型 | 线程安全。 原因:方法都用了synchronized | 线程不安全 |
2 ArrayList与LinkedList异同
相同点:
- 线程安全:都是线程不安全的
- 顺序:都是按照存入的顺序取出
不同点:
1. ArrayList的实现是基于数组,LinkedList的实现是基于双向链表。
2. 对于随机访问ArrayList要优于LinkedList,ArrayList可以根据下标以O(1)时间复杂度对元素进行随机访问,而LinkedList的每一个元素都依靠地址指针和它后一个元素连接在一起,查找某个元素的时间复杂度是O(N)。
3. 对于插入和删除操作,LinkedList要优于ArrayList,因为当元素被添加到LinkedList任意位置的时候,不需要像ArrayList那样重新计算大小或者是更新索引。
4. LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
HashMap是线程安全的吗?如果不是该如何解决?
1 HashMap是非线程安全的,在多线程环境下,多个线程同时触发HashMap时,有可能会发生冲突。所以,在多线程环境下不建议使用HashMap。
2 想要使用线程安全的HashMap,一共有三种办法:使用Hashtable,Hashtable是线程安全的。Hashtable是一个古老的API,从Java 1.0开始就出现了,它的同步方案还不成熟、性能不好,甚至官方都给出了不推荐使用的建议。
3 使用Collections将HashMap包装成线程安全的HashMap,Collections Collections类中提供了synchronizedMap()方法,可以将我们传入的Map包装成线程同步的Map。
使用ConcurrentHashMap,其中第三种方式最为高效,是我们最推荐的方式。 ConcurrentHashMap ConcurrentHashMap是线程安全且高效的HashMap,
在JDK 7中ConcurrentHashMap的底层数据结构为“数组+链表”,但是为了降低锁的粒度,JDK7将一个Map拆分为若干子Map,每一个子Map称为一个段。多个段之间是相互独立的,而每个段都包含若干个槽,段中数据发生碰撞时采用链表结构解决。在并发插入数据时,ConcurrentHashMap锁定的是段,而不是整个Map。因为锁的粒度是段,所以这种模式也叫“分段锁”。另外,段在容器初始化的时候就被确定下来了,之后不能更改。而每个段是可以独立扩容的,各个段之间互不影响,所以并不存在并发扩容的问题。 在JDK8中ConcurrentHashMap的底层数据结构为“数组+链表+红黑树”,但是为了进一步降低锁的粒度,JDK8取消了段的设定,而是直接在Map的槽内存储链表或红黑树。并发插入时它锁定的是头节点,相比于段头节点的个数是可以随着扩容而增加的,所以粒度更小。引入红黑树,则是为了在冲突剧烈时,提高查找槽内元素的效率。