【Java 并发】浅析同步容器类与并发容器类

【Java 并发】浅析同步容器类与并发容器类

一,同步容器类
最简单直接的理解:同步容器类就是将方法通过synchronized修饰达到线程安全的类。这些类实现线程安全的方式是:将状态封装起来,并对每个方法进行同步,使得即使在多线程,每一次也仅有一个线程可以访问容器的状态。结果变成了类似于串行执行的效果。仅仅只为实现同步。

常见的同步容器类
1,Vector(implements List),Hashtable(implements Map),Stack(extends Vector)。
2,Collections.synchronizedXxxx。

Vector中的部分方法
这里写图片描述

存在的问题
1,同步容器在单线程的环境下能够保证线程安全,但是通过synchronized同步方法将访问操作串行化,导致并发环境下效率低下。而且同步容器在多线程环境下的复合操作(迭代、条件运算如没有则添加等)是非线程安全,需要客户端代码来实现加锁。

public static Object getLast(Vector list) {  
    int lastIndex = list.size() - 1;  
    return list.get(lastIndex);  
}  

public static void deleteLast(Vector list) {  
    int lastIndex = list.size() - 1;  
    list.remove(lastIndex);  
}  

在多线程的情况,一个线程在调用getLast,同时另一个线程在调用deleteLast将元素删除,此时getLast将抛出越界异常。
可以在客户端通过获取容器类的锁,使得两个操作成为原子操作。虽然可以避免之前的问题,但是这也降低了并发的效率,而仅仅实现了同步。

public static Object getLast(Vector list) {
  synchronized(list){
      int lastIndex = list.size() - 1;  
    return list.get(lastIndex);  
}  
}

public static void deleteLast(Vector list) {  
  synchronized(list){
    int lastIndex = list.size() - 1;  
    list.remove(lastIndex);  
}  
}

2,迭代器与ConcurrentModificationException异常
因为“fail-fast”,当容器在迭代过程中被修改了,就会抛出ConcurrentModificationException异常。这种机制并不是一种完备机制,而只是告诉你并发错误。文档中也写到:it would be wrong to write a program that depended on thisexception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
解决办法就是整个迭代过程持有容器的锁,但是这这又很大程度降低并发效率。迭代规模很大时,就是有很多线程被阻塞等待锁。

二,并发容器类
同步容器类的存在的问题,使之成为鸡肋,食之无味,弃之可惜。于是就有了并发容器类来改进性能。
关于并发容器类的介绍,http://blog.csdn.net/u011080472/article/details/51418850#reply 中有详细介绍

1,锁分段
Hashtable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下Hashtable的效率非常低下。因为当一个线程访问Hashtable的同步方法时,其他线程访问Hashtable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。
Hashtable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问Hashtable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,

在ConcurrentHashMap中使用了一个包含16个锁的数组,每个锁保护所有散列桶的1/16,其中第N个散列桶由第(N mod 16)个锁来保护。假设使用合理的散列算法使关键字能够均匀的分部,那么这大约能使对锁的请求减少到越来的1/16。也正是这项技术使得ConcurrentHashMap支持多达16个并发的写入线程。

锁分段的劣势在于:当一个线程需要获得多个锁实现独占访问时将会更加困难,并且开销更大。比如要扩大ConcurrentHashMap容器,以及重新计算键值的散列值。

以上都是阅读《Java编程思想》-并发和《Java并发编程实践》的笔记,不喜勿喷!

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值