多线程下List 如何解决不安全问题
什么是线程安全与不安全
线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
为什么Lis是不安全的呢?show code
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(Thread.currentThread().getName()+list);
},String.valueOf(i)).start();
}
结果是
java.util.ConcurrentModificationException
为社么会这样?看看源码
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
我们可以看到,当添加元素之后,size还没有加加,如果此时另一个线程抢夺了cpu的资源,进行添加元素操作,size现在也是为0,然后之前的线程两个线程继续执行,结果就是有两个元素添加进去,但是当前容量为却是1.明白了吗
那么如何解决呢?
使用 Vector
为什么vector可以呢,看看源码
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
还可以有其他方式吗?
可以的,使用集合工具类 Collections.synchronizedList(new ArrayList<>()) 就可以创建一个安全的list,看看源码是怎么实现的
public void add(int index, E element) {
synchronized (mutex) {
list.add(index, element);
}
}
你说如果不想使用这个,还有没有其他的方法,还有哦
在java.util.concurrent的包下有 CopyOnWriteArrayList ,采用了读写分离思想,我们使用这个也是可以的,建议使用,我们来看看它的源码
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();
}
}
map 和 set 也存在不安全问题哦,解决方式也类似
本文地址:https://blog.csdn.net/qq_42224683/article/details/107335381
上一篇: JVM中堆、栈、方法区之间怎么交互
下一篇: Mybatis-Plus配置