第五章 站在巨人的肩膀上

本文聚焦Java同步容器类在多线程环境下的情况。同步容器类通过封装自身状态和对公共方法加锁实现同步,但仍可能出现问题。如常见复合操作若未在客户端代码加锁会出错,还列举了迭代、隐藏迭代等可能出现的情况及相应解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程5 站在巨人的肩膀上

同步容器类

同步容器类是通过对自身状态的封装,并对每个public方法进行加锁同步。通过Collections.synchronizedXxx()等创建的容器就是同步容器类,常用的有:vector、hashtable。
那么同步同步容易类是线程安全的吗?会出现问题吗?
答案:是线程安全而且有可能出现很严重的问题!

容器上的常见符合操作若没有在客户端的代码上加锁来保护就有可能出现错误。例如:迭代、条件运算、跳转(根据指定顺序找到当前元素的下一个元素)

例举几种可能出现的情况和解决办法

1、同步容器类Vector上有两个方法getLast和deleteLast,都会有“如果没有就添加”的操作。如果线程A上调用getLast线程B上调用deleteLast,这些操作交替执行,如下图中请求一个不存在的元素,就会出错。这时候就要在客户端加锁,但会牺牲一些伸缩性和并发性。
A→ size(10) ——————→get(9)→错误
B→ size(10)→remove(9)
2、迭代的标准方式都是使用Iterrator。如果容器没有加锁,对容器进行迭代的时候,其他线程并发的修改了这个容器,就会出现一种及时失败的问题,抛出异常(ConcurrentModificationException)。他并不是一种完善的处理机制,所以只能用做预警指示器。想要避免就必须在迭代的过程持有容器的锁,如果是个共享容器就需要在所有迭代的地方加锁。也可以通过克隆容器并在副本上迭代解决(克隆的过程仍需加锁),但是有显著的性能开销取决因素可能有容器大小、元素执行的负责度、调用其他容器的频率、响应时间和吞吐量等
3、隐藏迭代 system.out.pringln(“字符串A”+容器A),编译器将字符转换为StringBuilder.append又会调用容器的toString,标准容器中的toString将进行迭代,这时候就有可能例2的情况。hashCode, equals, containsAll, removeAll, retainAll, 以其他容器为参数的构造器也会进行隐性迭代

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值