[置顶] 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进行操作,也就不会有上述情况出现。 从这个错误来看的话,编程一定要谨慎,使用到的技术一定要深入了解,不能说不出问题,但是在出了问题之后能找出原因并解决,如果没有这个把握就不要轻易去使用,尤其在正式项目中,可能会让你欲哭无泪啊!
相关文章推荐
- java实际开发中泛型使用需要注意的一些问题
- Java中使用同步关键字synchronized需要注意的问题
- Delphi中多线程下使用使用 UniDAC+MSSQL 需要注意的问题(连接前调用CoInitialize)
- Delphi中多线程下使用使用 UniDAC+MSSQL 需要注意的问题
- 声明方法java实际开发中泛型使用需要注意的一些问题
- Twitter的分布式自增ID算法snowflake的JAVA实现以及使用时需要注意的问题
- 多线程下使用使用 UniDAC+MSSQL 需要注意的问题(使用CoInitialize)
- STL list在多线程下使用需要注意的问题
- Qt 多线程与数据库操作需要注意的几点问题(QSqlDatabase对象只能在当前线程里使用)
- Delphi中多线程下使用使用 UniDAC+MSSQL 需要注意的问题 .
- 在windows开发环境中,java代码中使用linux格式路径的方法需要注意的问题
- Twitter的分布式自增ID算法snowflake的JAVA实现以及使用时需要注意的问题
- 在windows开发环境中,java代码中使用linux格式路径的方法需要注意的问题
- 使用java.lang.Integer需要注意的一个问题
- java中使用list.remove需要注意的问题
- java中使用堆外内存,关于内存回收需要注意的事和没有解决的遗留问题(等大神解答)
- java 使用AtomicStampedReference解决ABA问题需要注意的坑
- Java中使用同步关键字synchronized需要注意的问题
- Java: ByteBuffer在多线程中使用需要注意
- 编写多线程java程序时需要注意哪些问题?(来自于effective java se)