0
点赞
收藏
分享

微信扫一扫

JDK源码——Vector类同步容器(如Vector)并不是所有操作都线程安全!

yeamy 2023-03-21 阅读 49


同步容器(如Vector)并不是所有操作都线程安全!

import java.util.Vector;

/**
* Copyright (C), 2018-2020
* FileName: Thread_vetcor
* Author: xjl
* Date: 2020/8/19 12:06
* Description: Vector线程安全
*/

public class Thread_vetcor {

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); //往vector中添加元素
}
Thread removeThread=new Thread(new Runnable() {
@Override
public void run() {
//获取vector的大小
for(int i=0;i<vector.size();i++){
//当前线程让出CPU,使例子中的错误更快出现
Thread.yield();
//移除第i个数据
vector.remove(i);
}
}
});
Thread printThread=new Thread(new Runnable() {
@Override
public void run() {
//获取vector的大小
for(int i=0;i<vector.size();i++){
//当前线程让出CPU,使例子中的错误更快出现
Thread.yield();
//获取第i个数据并打印
System.out.println(vector.get(i));
}
}
});
removeThread.start();
printThread.start();
//避免同时产生过多线程
while(Thread.activeCount()>20);
}
}
}

报错:

Exception in thread "Thread-19" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 4
at java.util.Vector.get(Vector.java:748)
at Thread_vetcor$2.run(Thread_vetcor.java:40)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "Thread-46" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 11
at java.util.Vector.remove(Vector.java:831)
at Thread_vetcor$1.run(Thread_vetcor.java:28)
at java.lang.Thread.run(Thread.java:748)

源码:vector的源码方法都使用synchronized关键字但是还是不安全呢?

public synchronized void copyInto(Object[] anArray) {
System.arraycopy(elementData, 0, anArray, 0, elementCount);
}


public synchronized void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (elementCount < oldCapacity) {
elementData = Arrays.copyOf(elementData, elementCount);
}
}

public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
modCount++;
ensureCapacityHelper(minCapacity);
}
}

public synchronized void setSize(int newSize) {
modCount++;
if (newSize > elementCount) {
ensureCapacityHelper(newSize);
} else {
for (int i = newSize ; i < elementCount ; i++) {
elementData[i] = null;
}
}
elementCount = newSize;
}

public synchronized int capacity() {
return elementData.length;
}

public synchronized int size() {
return elementCount;
}

解释:Vector里一些写删操作的方法都是用synchronized实现同步。尽管vector中的contains()方法和 add()方法都是同步的。但是组合应用时还是存在现场安全问题。

假如有两个线程同时进入put()方法,传递的参数都是一样的,例如 put("123")。当线程1执行if (!vector.contains(element)) 后还没有执行vector.add(element); 时,线程2进来了,此时vector.contains(element))还是返回false,这样的结果会导致两个123都加入到vector。所以是线程不安全的。

例子中 removeThread线程先调用了vector.size()方法获得vector的大小,接着调用vector.remove(i)移除第i个元素;而printThread线程也先调用vector.size()方法获得vector的大小,接着调用vector.get()获得第i个元素。

假设此时vector大小为5,此时printThread线程执行到 i=4 ,进入for循环但在 System.out.println(vector.get(i));之前 printThread线程的CPU时间片已到,线程printThread转入就绪状态;
此时removeThread线程获得CPU开始执行,把vector的5个元素全删除了,这是removeThreadCPU时间片已到;
接着printThread获得CPU进行执行,由于之前printThread中的i==4,于是调用vector.get(4)获取元素,此时由于vector中的元素已被removeThread线程全部删除,因此报错。

总的来说,vector保证了其同步方法不能被两个及两个以上线程同时访问,但是我们自己的操作会使得即使使用了Vector线程也不安全,如果不大清楚,最好自己加上 synchronized进行同步吧。

举报

相关推荐

0 条评论