1. ConcurrentHashMap类
ConcurrentHashMap是JDK1.5引入的一个集合类,它继承了Map接口,与Map接口的其它子类一样,ConcurrentHashMap没有对其方法进行扩充,但是,在底层却进行了天翻地覆的改变。
上一节介绍了的HashMap和Hashtable子类(Java 集合类 5-HashMap,Hashtable类),或多或少都有一些缺点,例如线程安全啊,执行效率等问题。而ConcurrentHashMap的引入,就是为了弥补这两个类的缺陷。
ConcurrentHashMap的特点 = Hashtable的线程安全性 + HashMap的高性能,在使用ConcurrentHashMap处理的时候,既可以保证多个线程更新数据的同步,又可以保证很高效的查询速度。
ConcurrentHashMap定义:
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable
ConcurrentHashMap的使用方法和HashMap一致。可以存放key值重复对象,新的value会将旧的value覆盖。但是,不允许存放null,key和value都不能存放。
使用方法如下:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Test {
public static void main(String[] args) {
// ConcurrentHashMap
Map<Integer, String> map = new ConcurrentHashMap<>();
map.put(1, "xucc");
map.put(1, "licc");
map.put(2, "sunn");
map.put(3, "zhzz");
System.out.println(map);
}
}
运行结果:
ConcurrentHashMap底层也是采用数组链表组合,红黑树两种方式实现的。当数组元素个数小于阈值(默认为8)采用数组分桶,桶上挂链表的形式进行元素存储。元素个数较多时,采用红黑树进行存储。
分桶依据一般采用的是对象的hasCode()方法,分桶的好处将保存的大量数据平均分在不同的桶(数据区域),这样在进行数据查找的时候就可以避免全
局的数据扫描。
另外,ConcurrentHashMap有一个显著的优点是写异步,读同步。写入数据时,为了防止线程不安全,所以采用异步的方式;而读数据是一个安全操作,所以采用同步方法。这样做,大大提高了操作的效率。
利用这种 数据更新的时候只锁更新的对应区域,其他区域的访问不受影响的特性,我们可以把ConcurrentHashMap应用在很多场景下,例如下面的外卖订餐系统的设计:
外卖小哥在送餐过程中任意时刻进行位置的更新以及相关信息的记录,相当于将信息进行写入,写入时,异步操作,同一时刻任何一个外卖小哥只能有一个人在操作。而对于订餐者和客服来讲,他们只需要了解这些信息就行了,读操作对线程来说没有危险,所以可以采用同步操作。
2. TreeMap类
TreeMap也是继承于Map接口的一个类,它的底层是用红黑树实现的。
它的定义如下:
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
TreeMap是一个可以排序的Map子类,它按照Key的内容进行升序排序。在Set接口里,有一个实现类TreeSet,它与TreeMap非常相似,唯一不同的是,TreeMap存入的元素是key-value键值对,而TreeSet只存入一个元素,具体可以参考:
和TreeSet一样,TreeMap的排序功能必须依赖于key对象继承Comparable接口并覆写compareTo()方法,只有这样,TreeMap才能按照key将存入的对象按照升序存放。
使用如下:
import java.util.Map;
import java.util.TreeMap;
public class Test {
public static void main(String[] args) {
// ConcurrentHashMap
Map<Integer, String> map = new TreeMap<>();
map.put(1, "xucc");
map.put(3, "licc");
map.put(4, "sunn");
map.put(2, "zhzz");
System.out.println(map);
}
}
运行结果:
关于继承Comparable接口这里再说两句。
有Comparable出现的地方,判断数据就依靠compareTo()方法完成,例如TreeMap,TreeSet等
而没有继承Comparable接口的子类,要想实现对象的排序或者比较,就要借助对象覆写过的equals()与hashCode()方法,例如HashSet,HashMap,Hashtable,ConcurrentHashMap等子类。