Java 数组集合(一)List
Java 数组集合(二)Set
Map
HashMap
HashMap根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。HashMap最多允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,及任意时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。
ConcurrentHashMap
Segment
ConcurrentHashMap和Hash Map类似,但是ConcurrentHashMap能够支持并发操作,所以要复杂一点。整个ConcurrentHashMap有一个个Segment组成,Segment代表“部分”或“一段”的意思,所以很多地方都会将其描绘为分段锁。
线程安全
ConcurrentHashMap是一个Segment数组,Segment通过继承ReentrantLock来进行加锁,所以每次需要加锁的操作锁住的是一个Segment,这样只要保证每个Segment是线程安全的,也就实现了全局的线程安全。
并发度
concurrencyLevel:
并行级别、并发数、Segment数,默认是16.
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
public class ConcurrentHashMapTest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
// 创建
ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<Integer, String>();
CountDownLatch countDownLatch = new CountDownLatch(2);
Runnable runnable = () -> {
for (int i = 1; i < 5; i++) {
String value = chm.get(i);
if (value == null) {
value=""+i;
chm.put(i, value);
} else {
chm.put(i, value + 1);
}
}
countDownLatch.countDown();
};
// 两个线程操作同一个key,可能会出现覆盖的现象,导致key的值小于10
new Thread(runnable).start();
new Thread(runnable).start();
countDownLatch.await();
System.out.println(chm);
}
// 基本操作
public static void ConcurrentHashMap_Test(ConcurrentHashMap<Integer, String> chm) {
// 添加
for (int i = 65; i < 91; i++) {
String str = "" + (char) i;
chm.put(i, str);
}
// size()
System.out.println("size = " + chm.size());
// 输出
System.out.println("遍历");
for (Entry<Integer, String> entry : chm.entrySet()) {
if (entry.getKey() > 77) {
Integer key = entry.getKey();
String value = entry.getValue();
System.out.print(key + " => " + value);
System.out.println();
}
}
}
}
HashTable
HashTable是遗留类,很多映射的常用功能与HashMap类似,不同的是它承自Dictionary类,并且是线程安全的,任意时刻只有一个线程能够改写HashTable,并发性不如ConcurrentHashMapp,因为ConcurrentHashMap引入了分段锁。HashTable不建议在新代码使用,不需要线程安全的场合可以用HashTable替换,需要线程安全的场合可以用ConcurrentHashMap替换。
import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
public class HashTableTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Hashtable<Integer, String> ht = new Hashtable<Integer, String>();
// HashTable_Test(ht);
// HashTable_Sort(ht);
HashTable_T(ht);
}
// 多线程
public static void HashTable_T(Hashtable<Integer, String> ht) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
ht.put(i, "thread value" + i);
try {
Thread.sleep(new Random().nextInt(1));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (ht) {// 迭代必须同步
if (ht.size() > 0) {
for (Map.Entry entry : ht.entrySet()) {
System.out.println(entry.getKey() + " => " + entry.getValue());
}
}
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
thread.start();
thread2.start();
}
// 排序
public static void HashTable_Sort(Hashtable<Integer, String> ht) {
ht.put(5, "EE");
ht.put(22, "QQ");
ht.put(26, "ZZ");
ht.put(3, "CC");
ht.put(7, "GG");
ht.put(1, "AA");
System.out.println(ht);
}
// 基本操作
public static void HashTable_Test(Hashtable<Integer, String> ht) {
// 添加
for (int i = 65; i < 91; i++) {
String str = "" + (char) i;
ht.put(i, str);
}
// size()
System.out.println("size = " + ht.size());
// 输出
System.out.println("遍历");
for (Entry<Integer, String> entry : ht.entrySet()) {
if (entry.getKey() < 88) {
Integer key = entry.getKey();
String value = entry.getValue();
System.out.print(key + " => " + value);
System.out.println();
}
}
}
}
TreeMap
TreeMap实现SortedMap接口,能够把它保存的纪录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排序过的。在使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出ClassCatException类型的异常。
import java.util.TreeMap;
import java.util.Map.Entry;
public class TreeMapTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 创建
TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
//
// TreeMap_Test(tm);
}
// 基本操作
public static void TreeMap_Test(TreeMap<Integer, String> tm) {
// 添加
for (int i = 65; i < 91; i++) {
String str = "" + (char) i;
tm.put(i, str);
}
// size()
System.out.println("size = " + tm.size());
// 输出
System.out.println("遍历");
for (Entry<Integer, String> entry : tm.entrySet()) {
if (entry.getKey() < 88) {
Integer key = entry.getKey();
String value = entry.getValue();
System.out.print(key + " => " + value);
System.out.println();
}
}
}
//Person
public static void TreeMap_Person() {
TreeMap<Integer, Person> tmp = new TreeMap<Integer, Person>();
for (int i = 0; i < 30; i++) {
int age = (int) (Math.random() * 20 + 1);
String name = "" + (char) (int) (Math.random() * 90 + 64);
tmp.put(i, new Person(name, age));
}
for (Entry<Integer, Person> entry : tmp.entrySet()) {
Integer key = entry.getKey();
Person value = entry.getValue();
System.out.print(key + " => " + value);
System.out.println();
}
}
}
class Person implements Comparable<Object> {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
Person person = (Person) o;
if (this.age > person.age) {
return 1;
}
if (this.age < person.age) {
return -1;
}
return this.name.compareTo(person.name);
}
}
LinkedHashMap
LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,在使用Iterator遍历LinkedHashMap时,先得到的纪录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。
import java.util.LinkedHashMap;
import java.util.Map.Entry;
public class LinkedHashMapTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 创建
LinkedHashMap<Integer, String> lhm = new LinkedHashMap<Integer, String>();
LinkedHashMap_Test(lhm);
}
// 基本操作
public static void LinkedHashMap_Test(LinkedHashMap<Integer, String> lhm) {
// 添加
for (int i = 65; i < 91; i++) {
String str = "" + (char) i;
lhm.put(i, str);
}
// size()
System.out.println("size = " + lhm.size());
// 输出
System.out.println("遍历");
for (Entry<Integer, String> entry : lhm.entrySet()) {
if (entry.getKey() < 88) {
Integer key = entry.getKey();
String value = entry.getValue();
System.out.print(key + " => " + value);
System.out.println();
}
}
}
}
LRU(Least Recently Used):
LRU:最近最久未使用策略,优先淘汰最久未使用的数据,也就是上次被访问时间距离现在最久的数据。该策略可以保证内存中的数据都是热点数据,也就是经常被访问的数据,从而保证缓存命中率。
使用LinkedHashMap实现
LinkedHashMap底层就是用的【HashMap】加【双链表】实现的,而且本身已经实现了按照访问顺序的存储。此外,LinkedHashMap中本身就实现了一个方法removeEldestEntry用于判断是否需要移除最不常读取的数,方法默认是直接返回false,不会移除元素,所以需要【重写该方法】,即当缓存满后就移除最不常用的数。
HashMap、ConcurrentHashMap、HashTable、TreeMap、LinkedHashMap
- HashMap、TreeMap、LinkHashMap线程不安全,
- ConcurrentHashMap、HashTable线程安全