我们这里来介绍一点其他的集合类
Linkedhashmap在原来的基础上维护了一个双向链表,用来维护,插入的顺序。
public class LinkedHashMapTest {
public static void main(String[] args){
Map<String,String> map = new LinkedHashMap<>(16);
map.put("a","m");
map.put("b","n");
map.put("c","o");
map.put("d","p");
map.put("e","q");
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
System.out.println(next.getKey());
System.out.println(next.getValue());
}
}
}
我们看一下Linkedhashmap的构造器
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
这只是一个空参构造
原文对于accseeOrder的解释是这样的
accessOrder – the ordering mode - true for access-order, false for insertion-order
// accessOrder为true的话,则会把访问过的元素放在链表后面,放置顺序是访问的顺序 如果accessOrder为flase的话,则按插入顺序来遍历
可以用这个集合实现LRU算法
public class LRU<K,V> extends LinkedHashMap<K,V> {
private int max_capacity;
public LRU(){
super(16,0.75F,true);
max_capacity = 8;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > max_capacity;
}
}
TreeMap底层实现是红黑树,所以天然支持排序。
我们看一下她的源码
public TreeMap() {
comparator = null;
}
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
final int compare(Object k1, Object k2) {
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
: comparator.compare((K)k1, (K)k2);
}
他有两个构造器,我们实现一下空参构造
Map<Dog,String> map = new TreeMap<>();
for (int i = 0; i < 100; i++) {
map.put(new Dog(),"a");
}
报错,没有定义比较器,我们定义一个比较器
Map<Integer,String> map = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
for (int i = 0; i < 100; i++) {
map.put(i,"a");
}
// 我们发现已经自动排序了
System.out.println(map);
Collections是一个工具类,它给我们提供了一些常用的好用的操作集合的方法。
ArrayList<Integer> list = new ArrayList<>();
list.add(12);
list.add(4);
list.add(3);
list.add(5);
//将集合按照默认的规则排序,按照数字从小到大的顺序排序
Collections.sort(list);
System.out.println("list = " + list);
//将集合中的元素反转
Collections.reverse(list);
System.out.println("list = " + list);
//addAll方法可以往集合中添加元素,也可往集合中添加一个集合
Collections.addAll(list,9,20,56);
//打乱集合中的元素
Collections.shuffle(list);
System.out.println("list = " + list);
//Arrays.asList方法可以返回一个长度内容固定的List集合
List<String> list2 = Arrays.asList("tom", "kobe", "jordan", "tracy","westbook","yaoming","ace","stephen");
//按照字符串首字符的升序排列
Collections.sort(list2);
使用增强for循环中删除元素会抛异常,其实不仅仅是删除元素,增加元素也会导致异常
public void StrangerFor() {
for (Integer array:arrayList) {
arrayList.remove(array);
System.out.println(array);
}
}
迭代器是依赖于集合而存在的,在判断成功后,集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。
我们知道当多个线程同时操作共享资源时会有线程安全问题。我们试着去产生一下这个问题
ArrayListTest arrayListTest = new ArrayListTest();
for (int i = 0; i < 1000; i++) {
new Thread(()->{
ArrayListTest.arrayList.add(1);
}).start();
}
System.out.println(arrayList.size());
最后添加的数据并不到1000个,总是差两三个
那怎么解决线程安全的问题啊。加锁,只能有一个线程去操作这个集合
HashMap和HashTable区别
ArrayList和Vector的区别
CopyOnWriteList的核心就是写入的时候加锁,保证线程安全,读取的时候不加锁。不是一股脑,给所有的方法加锁。
ConcurrentHashMap和HashMap的代码基本一样,只不过在有些操作上使用了cas,有些地方加了锁。
JDK8以前是头插法,JDK8后是尾插法,那为什么要从头插法改成尾插法?
我们尝试开辟50个线程,每个线程向集合中put100000个元素,测试两个类所需要的时间。
@Test
public void hashtableTest() throws InterruptedException {
final Map<Integer,Integer> map = new Hashtable<>(500000);
final CountDownLatch countDownLatch = new CountDownLatch(50);
System.out.println("----------------开始测试Hashtable------------------");
long start = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
final int j = i;
new Thread(()->{
for (int k = 0; k < 100000; k++) {
map.put(j*k,1);
}
countDownLatch.countDown();
}).start();
}
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("hashtable:(end-start) = " + (end - start));
// ----------------开始测试ConcurrentHashMap------------------
System.out.println("----------------开始测试ConcurrentHashMap------------------");
final Map map2 = new ConcurrentHashMap<>(500000);
final CountDownLatch countDownLatch2 = new CountDownLatch(50);
start = System.currentTimeMillis();
for (int i = 0; i < 50; i++) {
final int j = i;
new Thread(()->{
for (int k = 0; k < 100000; k++) {
map2.put(j*k,1);
}
countDownLatch2.countDown();
}).start();
}
countDownLatch.await();
end = System.currentTimeMillis();
System.out.println("ConcurrentHashMap:(end-start) = " + (end - start));
}
最后我们发现ConcurrentHashMap真的比HashTable快了很多
谷歌的程序员无聊的时候搞得一个工具包