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.