多线程使用Vector或HashTable

简介:

Vector是ArrayList的多线程版本,HashTable是HashMap的多线程版本,这些概念我 们都很清楚,也被前辈嘱咐过很多次,但我们经常会逃避使用Vector和HashTable,因为用 得少,不熟嘛!只有在真正需要的时候才会想要使用它们,但问题是什么时候算真正需要呢?我们来看一个例子,看看使用线程安全的Vector是否可以解决问题,代码如下:

复制代码
 1 import java.util.ArrayList;
 2 import java.util.List;
 3 import java.util.Random;
 4 
 5 public class Client {
 6 
 7     public static void main(String[] args) {
 8         // 火车票列表
 9         //final List<String> tickets = new Vector<String>();
10         final List<String> tickets = new ArrayList<String>();
11         // 初始化票据池
12         for (int i = 0; i < 100000; i++) {
13             tickets.add("火车票" + i);
14         }
15 
16         // 退票
17         Thread returnThread = new Thread() {
18             public void run() {
19                 while (true) {
20                     tickets.add("车票" + new Random().nextInt());
21                 }
22             };
23         };
24 
25         // 售票
26         Thread saleThread = new Thread() {
27             public void run() {
28                 for (String ticket : tickets) {
29                     tickets.remove(ticket);
30                 }
31             };
32         };
33 
34         // 启动退票线程
35         returnThread.start();
36         // 启动售票线程
37         saleThread.start();
38 
39     }
40 }
复制代码

 

模拟火车站售票程序,先初始化一堆火车票,然后开始出售,同时也有退票产生,这段程序有没有问题?可能会有读者看出了问题,ArrayList是线程不安全的,两个线程访问同一 个ArrayList数组肯定会有问题。

没错,确定有问题,运行结果如下:

Exception in thread "Thread-1" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at cn.summerchill.test.Client$2.run(Client.java:30)

 

运气好的话,该异常马上就会报出。也许有人会说这是一个典型错误,只须把ArrayList 替换成Vector即可解决问题,真的是这样吗?我们把ArrayList替换成Vector后,结果照旧,仍然抛出相同的异常,Vector已经是线程安全的,为什么还报这个错误呢?

这是因为他混淆了线程安全和同步修改异常,基本上所有的集合类都有一个叫做快速失败(Fail-Fast)的校验机制,当一个集合在被多个线程修改并访问时,就可能会出现 ConcurrentModificationException异常,这是为了确保集合方法一致而设置的保护措施,它 的实现原理就是我们经常提到的modCmmt修改计数器:如果在读列表时,modCount发生变 化(也就是有其他线程修改)则会抛出ConcurrentModificationException异常。

这与线程同 步是两码事,线程同步是为了保护集合中的数据不被脏读、脏写而设置的,我们来看线程安 全到底用在什么地方,代码如下:

复制代码
 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class Client {
 5     
 6     public static void main(String[] args) {
 7         //火车票列表
 8         final List<String> tickets = new ArrayList<String>();
 9         //初始化票据池
10         for(int i=0;i<100000;i++){
11             tickets.add("火车票" + i);
12         }
13         //10个窗口售票
14         for(int i=0;i<10;i++){
15             new Thread(){
16                 public void run() {
17                     while(true){
18                         System.out.println(Thread.currentThread().getId() +"——"+ tickets.remove(0));
19                     }
20                 };
21             }.start();
22         }
23         
24         
25     }
26 }
复制代码

 

还是火车站售票程序,有10个窗口在卖火车票,程序打印出窗口号(也就是线程号)和车票编号,很快我们就会看到这样的输出:

注意看,上面有两个线程在卖同一张火车票,这才是线程不同步的问题,此时把ArrayList修改为Vector即可解决问题,因为Vector的每个方法前都加上了 synchronized关 键字,同时只会允许一个线程进入该方法,确保了程序的可靠性。

虽然在系统开发中我们一再说明,除非必要,否则不要使用synchronized,这是从性能 的角度考虑的,但是一旦涉及多线程时(注意这里说的是真正的多线程,不是并发修改的问 题,比如一个线程增加,一个线程删除,这不属于多线程的范畴),Vector会是最佳选择,当 然自己在程序中加synchronized也是可行的方法。

HashMap的线程安全类HashTable与此相同,不再赘述。

 


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5660179.html,如需转载请自行联系原作者

相关文章
|
1月前
|
负载均衡 安全 算法
深入解析线程安全的Hashtable实现
深入解析线程安全的Hashtable实现
|
存储 安全
线程进阶 --- HashMap、HashTable和ConcurrentHashMap
线程进阶 --- HashMap、HashTable和ConcurrentHashMap
92 0
线程进阶 --- HashMap、HashTable和ConcurrentHashMap
|
13天前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
25天前
|
存储 缓存 NoSQL
Redis单线程已经很快了6.0引入多线程
Redis单线程已经很快了6.0引入多线程
31 3
|
27天前
|
消息中间件 安全 Linux
线程同步与IPC:单进程多线程环境下的选择与权衡
线程同步与IPC:单进程多线程环境下的选择与权衡
57 0
|
1月前
|
Java 调度 C#
C#学习系列相关之多线程(一)----常用多线程方法总结
C#学习系列相关之多线程(一)----常用多线程方法总结
|
1月前
|
安全 编译器 C#
C#学习相关系列之多线程---lock线程锁的用法
C#学习相关系列之多线程---lock线程锁的用法

热门文章

最新文章