同步容器:
ArrayList--->Vector,Stack
HashMap--->HashTable(key,value不能为null)
Collections.synchronizedXXX(List、Set、Map)
同步容器并不是所有的场合都是线程安全的。
例如:
package com.liuhy.test.testapplication.syncContainer;
import java.util.Vector;
/**
* @Auther: liuhy
* @Date: 2018/12/3 11:20
*
* 这样的写法线程不安全
*/
public class VectorExample2 {
private static Vector<Integer> vector = new Vector<>();
public static void main(String[] args) {
while (true) {
for (int i = 0; i < 10; i++) {
vector.add(i);
}
//启动线程
Thread thread = new Thread(() -> {
for (int i = 0; i < vector.size(); i++) {
vector.remove(i);
}
});
//启动线程1
Thread thread1 = new Thread(() -> {
for (int i = 0; i < vector.size(); i++) {
vector.get(i);
}
});
thread.start();
thread1.start();
}
}
}
说明:这种写法get会抛下标越界,因为执行顺序的问题,假如Vector最大下标为10,当remove(10)先执行,而get(10)后执行,就会导致下标越界。对这样的场景,我们需要做额外的处理,保证其线程安全性。
集合中容易出错的场景
package com.liuhy.test.testapplication.syncContainer;
import java.util.Iterator;
import java.util.Vector;
/**
* @Auther: liuhy
* @Date: 2018/11/30 11:04
*/
public class VectorExample3 {
private static void test1(Vector<Integer> v1){
for(Integer i: v1){
if(i.equals(3)){
v1.remove(2);
}
}
}
private static void test2(Vector<Integer> v1){
Iterator<Integer> iterator = v1.iterator();
while (iterator.hasNext()){
Integer next = iterator.next();
if(next.equals(3)){
v1.remove(next);
}
}
}
private static void test3(Vector<Integer> v1){
for (int i = 0; i < v1.size(); i++) {
if(v1.get(i).equals(3)){
v1.remove(i);
}
}
}
public static void main(String[] args) {
Vector<Integer> integers = new Vector<>();
integers.add(1);
integers.add(2);
integers.add(3);
test3(integers);
}
}
说明:当使用foreach、iterator遍历集合的时候,对集合做移除操作,容易抛出异常Exception in thread "main" java.util.ConcurrentModificationException;for循环遍历不会抛异常;引申出:多线程场景下,对同一个集合进行遍历和remove操作即易抛出异常。可以使用并发容器等避免该问题。
同步容器使用synchronized修饰性能不是太高,而且不一定能保证所有的场景都线程安全,所以使用的场景越来越少,通常使用并发容器代替。