
引入:集合类不安全
例:使用多线程操作List<String>
代码
1 | public class Demo9_多线程操作字符串ArrayList { |
输出
1 | [058ac] |
java.util.ConcurrentModificationException
上面例子中出现了java.util.ConcurrentModificationException
异常。
java.util.ConcurrentModificationException
异常,即:并发修改异常。
结论:并发下ArrayList 不安全。
解决方案
List<String> list = new Vector<>();
Vector是线程安全的,ArrayList是线程不安全的。
在
Vector
类下,add()
方法带有synchronized
修饰;ArrayList
下的add()方法没有synchronized
修饰。List<String> list = Collections.synchronizedList(new ArrayList<>());
( JUC方案 )
List<String> list = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList
写入时复制
原理
首先把原数组复制一份,然后把要添加的内容添加进新数组,最后将新的数组直接赋值给原引用。
1 | public boolean add(E e) { |
- 写入时复制
- 读写分离
CopyOnWriteArrayList
和 Vector
CopyOnWriteArrayList效率比Vector高。
Set不安全
例:使用多线程操作Set<String>
代码
1 | public class Demo10_多线程操作字符串Set { |
输出
1 | [1cb01, eb758, aa01b, 9af06, c57bf, 847f3, 2b7e6, e2f07, 96c2f, bc219, b0027] |
出现了错误java.util.ConcurrentModificationException
。
解决方案
Set<String> set = Collections.synchronizedSet(new HashSet<>());
- ( JUC方案 )
Set<String> set = new CopyOnWriteArraySet<>();
HashSet
底层
1 | public HashSet() { |
HashSet
的底层是HashMap
。
多线程的HashMap
引入:
Map<String,String> map = new HashMap<>();
map是这么用的吗?默认等价于什么?
不是这样用的。用法:Hole….(挖坑,后续填)
默认等价于new HashMap<>(16,0.75)
HashMap
HashMap
是一个集合,键值对的集合,每个节点用Node<K,V>表示
Node
1 | static class Node<K,V> implements Map.Entry<K,V> { |
Node是一个内部类,key为键,value为值,next指向下一个元素。
数据结构
HashMap的数据结构为:数组+(链表或红黑树)
- 在JDK1.8之前,HashMap的数据结构为“数组 + 链表”,数组是HashMap的主体,链表则是为了解决哈希冲突问题;
- Jdk1.8之后,当链表长度大于阈值(或者红黑树的边界值,默认为8),并且当前数组长度大于64时,此索引位置上的所有数据改为使用红黑树存储。
注:若链表长度大于64,但数组长度小于64,此时并不会将链表转换为红黑树,而是进行数组扩容。
因为红黑树需要保持平衡,影响效率,为了提高性能和减少搜索时间,当链表长度大于阈值且数组长度大于64时,链表才会转换为红黑树。
HashMap的构造函数
1 | public HashMap(int initialCapacity, float loadFactor) { |
HashMap有两个参数:initialCapacity 和 loadFactor (初始容量和加载因子)
- 初始容量是创建时数组分配的容量大小,默认为16;
- 加载因子
1 | final V putVal(int hash, K key, V value, boolean onlyIfAbsent, |
例:使用多线程操作Set<String>
代码
1 | public class Demo11_多线程操作HashMap { |
输出
1 | {0=c16d6, 1=a939d, 3=96525, 4=27c75} |
解决方案
Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
- ( JUC方案 )
Map<String,String> map = new ConcurrentHashMap<>();
ConcurrentHashMap 介绍….-> Hole…
其他
随机生成字符串
UUID.randomUUID().toString()
可以随机生成字符串,使用substring(0,x)
取出其中一部分。