您的位置:首页 > 编程语言 > Java开发

[置顶] java Vector 在多线程使用中需要注意的问题

2017-04-27 11:14 393 查看
众所周知,Java中有一些被称为是线程安全的集合容器,但是这里的线程安全会让人误以为在多线程环境中去使用这些容器就可以放心使用,包打天下。但是事实上并不是如此,在多线程中使用这些类仍然会存在问题。这就让人迷茫了,明明是线程安全的,为什么还会出错呢。我的理解是,明明是线程安全的,但是这些集合并不一定能在多线程环境中不出问题。
先看一段测试代码:

public class VectorTest {
private static Vector testVector = new Vector();

public static void main(String arg[]) {
while (true) {
for (int i = 0; i < 10; i++) {
testVector.add(i);
System.out.println("add" + i);
}
Thread remove = new Thread() {
@Override
public void run() {
try {

for (int i = 0; i < testVector.size(); i++) {
testVector.remove(i);
System.out.println("remove" + i);
Thread.sleep(1000);
}

} catch (Exception e) {
e.printStackTrace();
}
}
};

Thread print = new Thread() {
@Override
public void run() {
try {

for (int i = 0; i < testVector.size(); i++) {
System.out.println(testVector.get(i));
Thread.sleep(1000);
}

} catch (Exception e) {
e.printStackTrace();
}
}
};

print.start();
remove.start();
while (Thread.activeCount() > 10) ;
}


(这段代码是在看《深入理解java 虚拟机》这本书看到的)

这段代码如果不运行可能看不出来问题,甚至运行了也不一定能暴露出问题,这里有一个很微妙的时机问题,等会儿具体分析。先看一下遇到的异常信息:




这就是所谓的线程安全的类,在多线程中一样会有问题,那这是为什么呢,刚开始我也是百思不得姐,哦,是百思不得其解。后来在一篇博文当中看到了说Vector的contains方法和remove方法之前不具备原子性,这点给了提示。我现在认为出错的
4000
原因是在get和remove之间并没有在以上环境中做到同步,比方说,一个线程的get(2)操作发生时,正好遇到了remove操作的正在进行,这时get(2)这个操作就会阻塞,等待remove操作释放锁之后去操作。如果这时候remove操作的正好是remov(2)这个操作,等到去get的时候,这个元素已经没有了,get自然就只能是空欢喜一场。
这里原因找到了,就该说解决办法了,在说解决办法之前,可能还会困惑,说好的线程安全呢,是不是童话里都是骗人的啊?我的理解是,线程安全并不代表使用安全,在实际使用时还是需要考虑当前环境中是否会出现问题的。那么问题来了,java提供线程安全的某些类的意义在哪里呢,反正还是会出问题。这就显得比较鸡肋了,但是也不能说没有意义,毕竟写程序还是要独立思考的。
解决办法就比较简单了,在两个线程的run方法里加上synchronized (testVector),这样就会使得读取、删除线程中只会有一个对testVector进行操作,也就不会有上述情况出现。
从这个错误来看的话,编程一定要谨慎,使用到的技术一定要深入了解,不能说不出问题,但是在出了问题之后能找出原因并解决,如果没有这个把握就不要轻易去使用,尤其在正式项目中,可能会让你欲哭无泪啊!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐