首先我们先看下几个概念
- 高并发和多线程的区别?
多线程:是java的特性
高并发::不是java特有的东西,和语言无关 - 同步和异步
同步:任务进行存在顺序(等待)
异步:多任务进行没有顺序(无需等待) - 并发和并行
并发:多个任务交替进行
并行:多个任务同时进行
什么是同步容器
通过synchronized关键字修饰的容器,保证同一个时刻内只有一个线程在使用这个容器,从而使得容器线程安全
什么是并发容器
允许多线程同时使用容器,并且保证线程安全.而为了达到尽可能的提高并发,java并发工具包中采用了多种优化方式来提高并发容器的执行效率. 核心: 锁,cas,cow(读写分离),分段锁
同步容器
Vector: 和Arraylist一样实现的List接口,区别在于Vector在可能出现线程不安全的所有方法都用了synchronized进行修饰
Stack: 是Vector的子类,Stock实现的是先进后出的栈,入栈,出栈都用了synchronized的关键字修饰
HashTable:实现Map接口,实现的功能和HashMap基本一致(HashTable不可能出现null,HashMap的键值可以存在null),HashTable也使用了synchronized修饰了方法
ArrayList,HashSet,HashMap这些都是线程不安全的,如何将这些线程不安全的转换成线程安全的呢?
Collections提供了同步集合类
List<Object> objects = Collections.synchronizedList(new ArrayList<>());
Map<Object, Object> objectObjectMap = Collections.synchronizedMap(new HashMap<>());
Set<Object> objects1 = Collections.synchronizedSet(new HashSet<>());
- 但是这种方式在多线程处理时效率是非常低的,在jdk1.5之后就提供的并发包,就可以解决多线下处理效率低的问题
CopyOnWriteArrayList : 写时复制容器.写的是时候,会先复制一个容器
读: 从原来容器读
写: 把数据写到新的容器中
List.add()方法
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//这个是将原数组拷贝一份
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
//将新的数组替换原来的数组
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
List.remove()方法
public E remove(int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
int numMoved = len - index - 1;
if (numMoved == 0)
//如果是移除最后一个元素,拷贝(0,len-1)的集合对象
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
//将原数组中从索引0开始拷贝index个元素,放到新中,从索引0开始
System.arraycopy(elements, 0, newElements, 0, index);
//将原数组中从index+1号元素开始拷贝,放到新数组中,拷贝len - index - 1个原素
//两次加起来一共拷贝len-1个元素
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
//替换原数组
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
list.get()方法
public E get(int index) {
//getArray()获取当前集合
return get(getArray(), index);
}
//获取集合对应索引的元素
private E get(Object[] a, int index) {
return (E) a[index];
}
以上是copyOnWriteArrayList的一些方法的源码,总结下来有两个缺点
1 占用系统资源,频繁创建对象
2 数据一致性问题: 只能保证最终一致性
ConcurrentHashMap :
在JDK1.7中:数组+链表+分段锁
在JDK1.8中:数组+链表+红黑树
1、当一个位置有多个元素的时候,ConcurrentHashMap优先采用链表的形式存储
2、如果链表的元素个数大于8个,并且数组的长度小于64,则扩容
3、如果链表的元素个数大于8个,并且数组的长度大于64,会将该节点的链表转换成红黑树

被折叠的 条评论
为什么被折叠?



