1.大纲
集合类的历史
ConcurrentHashMap
CopyConWriteArrayList
并发队列
一:容器的概览
1.概览
ConcurrentHashMap:线程安全的HashMap
CopyOnWriteArrayList:线程安全的List
BlockingQueue:这是一个接口,表示阻塞队列
ConcurrentLinkedQueue:高效的非阻塞并发队列,线程安全的,可以看做一个线程安全的LinkedList
ConcurrentSkipListMap:是一个map,使用跳表数据结构进行快速查找
二:集合历史
1.vector与Hashtable
vector:
package com.jun.juc.collections;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) {
Vector vector = new Vector();
vector.add("test");
System.out.println(vector.get(0));
}
}
看一下get方法
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
结论:
这个是在方法上加了锁,继续看其他的方法,发现也是在方法是加的锁。
Hashtable:
public class HashtableDemo {
public static void main(String[] args) {
Hashtable<String, String> stringStringHashtable = new Hashtable<>();
stringStringHashtable.put("aa", "1111");
System.out.println(stringStringHashtable.get("aa"));
}
}
看一下对应的get方法:
public synchronized V get(Object key) {
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return (V)e.value;
}
}
return null;
}
结论
也是在方法上加的锁进行实现的
2.ArrayList与HashMap
是线程不安全的,可以使用如下的方法使得安全:
Collections.synchronizedList(new ArrayList<>())
Collections.synchronizedMap(new HashMap<>())
示例:
package com.jun.juc.collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SynchronizedListAndMap {
public static void main(String[] args) {
List<String> strList = Collections.synchronizedList(new ArrayList<String>());
strList.add("tom");
}
}
进入:
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
这个时候,看一下ArrayList:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
所以,走第一个对象,然后再进去看:
/**
* @serial include
*/
static class SynchronizedRandomAccessList<E>
extends SynchronizedList<E>
implements RandomAccess {
SynchronizedRandomAccessList(List<E> list) {
super(list);
}
看父类:
/**
* @serial include
*/
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return list.hashCode();}
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
public int indexOf(Object o) {
synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {return list.lastIndexOf(o);}
}
public boolean addAll(int index, Collection<? extends E> c) {
synchronized (mutex) {return list.addAll(index, c);}
}
public ListIterator<E> listIterator() {
return list.listIterator(); // Must be manually synched by user
}
public ListIterator<E> listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user
}
public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedList<>(list.subList(fromIndex, toIndex),
mutex);
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
synchronized (mutex) {list.replaceAll(operator);}
}
@Override
public void sort(Comparator<? super E> c) {
synchronized (mutex) {list.sort(c);}
}
/**
* SynchronizedRandomAccessList instances are serialized as
* SynchronizedList instances to allow them to be deserialized
* in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
* This method inverts the transformation. As a beneficial
* side-effect, it also grafts the RandomAccess marker onto
* SynchronizedList instances that were serialized in pre-1.4 JREs.
*
* Note: Unfortunately, SynchronizedRandomAccessList instances
* serialized in 1.4.1 and deserialized in 1.4 will become
* SynchronizedList instances, as this method was missing in 1.4.
*/
private Object readResolve() {
return (list instanceof RandomAccess
? new SynchronizedRandomAccessList<>(list)
: this);
}
}
结论:
发现是使用代码块的方式进行的安全。
三:ConcurrentHashMap
1.Map的介绍

说明一下LinkedHashMap:
大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。HashMap的这一缺点往往会带来困扰,因为有些场景,我们期待一个有序的Map。
这个时候,LinkedHashMap就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。
2.为什么HashMap是线程不安全的
同时put碰撞会导致数据的丢失
同时put扩容会导致数据的丢失
死循环造成的cpu100%
3.为什么出现100%
主要存在于jdk7
需要使用多线程进行调试
package com.jun.juc.collections;
import java.util.HashMap;
/**
* 演示cpu100%
*/
public class HashMapLoop {
private static HashMap<Integer, String> map = new HashMap(2, 1.5f);
public static void main(String[] args) {
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
new Thread(new Runnable() {
@Override
public void run() {
map.put(4, "D");
System.out.println(map);
}
}, "thread1").start();
new Thread(new Runnable() {
@Override
public void run() {
map.put(5, "E");
System.out.println(map);
}
}, "thread1").start();
}
}
需要的断点:

然后,将两个线程都放到if()那行,然后都放行
原因:
因为在同时扩容时候,出现了链表的死循环,环形链表
4.