JCIP_4_01_扩展现有安全类_客户端加锁
来源:互联网 发布:英语网络 编辑:程序博客网 时间:2024/06/05 22:49
客户端加锁实践
对于类似由Collections.synchronizedList封装的ArrayList这种场景,客户端并不知道同步封装器工厂方法中返回的List对象的具体类型,这时需要对返回的List对象进行扩展,可以考虑只扩展类的功能,但不是扩展类本身,而是将扩展代码放入一个“辅助类”中。
该文档记下了在进行辅助类扩展现存线程安全类时,辅助类使用的锁和被扩展的类使用的锁不是同一个,出现了并发问题。所以通过辅助类加锁扩展现存线程安全类实例的功能,需要客户端明确知道被扩展的类实例使用的锁。
示例代码
package org.ybygjy.jcip.chap4;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.concurrent.CountDownLatch;/** * 锁在哪里的问题。 * <p>1、此代码验证客户端正确和不正确加锁的场景</p> * <p>2、可以观察到addIfAbsent并未符合我们的要求,从结果可以看到重复值</p> * <p> * 3、操作步骤 * 3.1、声明一个List的扩展类,该类负责扩展List的功能。 * 3.2、在扩展类中新加入addIfAbsent函数,该函数错误的使用了锁,导致扩展的list新特性不具有线程安全性 * 3.3、创建测试线程类,负责模拟测试环境 * 3.4、创建多个线程,并发读取和写入数据到list的扩展实例中 * 3.5、打印list扩展实例数据,观察测试结果 * <p> * 4、小结 * 4.1、通过添加原子操作来扩展现存类非常脆弱,因为这会将类的加锁代码分布到多个类中。 * 4.2、客户端加锁更加脆弱,因为它将原始类的加锁代码放到与原始类完全无关的其它类中。 * @author WangYanCheng * @version 2014年8月13日 */public class WhereAreTheLocks {private static final CountDownLatch latch = new CountDownLatch(6);/** * 测试执行入口 * @param args 参数列表 */public static void main(String[] args) {ListHelper calInst = new ListHelper();//声明6个线程for (int i = 0; i < 6; i++) {new TestThread("WhereAreTheLocks_" + i, calInst).start();}}/** * 测试线程类 * @author WangYanCheng * @version 2014年8月13日 */static class TestThread extends Thread {private ListHelper calInst;/** * 构造函数 * @param threadName 线程名称 * @param calInst {@link ListHelper} */public TestThread(String threadName, ListHelper calInst) {super(threadName);this.calInst = calInst;}@Overridepublic void run() {for (int i = 0; i < 21; i++) {long v = (long) (Math.random() * 10);if ((long)(Math.random() * 10) % 2 == 0) {calInst.add(v);} else {calInst.addIfAbsent(v);}try {sleep((long) (Math.random() * 1000));} catch (InterruptedException e) {e.printStackTrace();}}latch.countDown();try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName() + ">>" + calInst.toString());}}}/** * 声明List类的扩展类,该类负责扩展List的功能,但是该类因为使用了错误的锁,所以不具有线程安全性,该类仅仅带来了同步的假象。 * @author WangYanCheng * @version 2014年8月13日 */class ListHelper {/** * 1.声明支持并发操作的list变量 * 2.注意List在实现客户端加锁或外部加锁时使用同一个锁。 */public List<Object> list = (List<Object>) Collections.synchronizedList(new ArrayList<Object>());/** * 普通 * @param obj */public void add(Object obj) {synchronized(list) {if (list.contains(obj)) {return;}list.add(obj);}}/** * 如果当前list中不存在该元素则加入,否则不做任何操作 * <p>无论list使用哪一个锁来保护它的状态,我们可以确定的是,这个锁并不是</p> * @param obj * @return rtnFlag {true:存在未添加,false:不存在已添加} */public boolean addIfAbsent(Object obj) {synchronized(this) {boolean isAbsent = !this.list.contains(obj);String tmpStr = "T_" + obj;if (!isAbsent) {this.list.add(tmpStr);}return isAbsent;}}public String toString() {return list.toString();}}
参考资料
1、Java Concurrenty In Practice
0 0
- JCIP_4_01_扩展现有安全类_客户端加锁
- JCIP_4_01_扩展现有安全类
- JCIP_4_02_扩展现有安全类
- 客户端加锁
- 【多线程_提高】 在现有的线程安全的类中添加功能
- 阿里移动安全_验证码对抗之路及现有验证机制介绍
- Objective-c中通过分类来扩展现有类
- 加锁类
- 加锁类
- 对集合在客户端加锁
- SVN客户端给文件加锁
- 扩展joolma现有模块字段
- PHP文件加锁确保多线程写入安全
- 双重检查加锁机制--解决线程安全
- 同步容器,复合操作客户端加锁
- 使用分类向某个现有类添加方法(类扩展,范畴)
- 在现有系统基础上扩展storm
- 加锁基类LockImpl
- LeetCode: Linked List Cycle
- LeetCode: Linked List Cycle II
- C++ STL简介
- C++学习的50条忠告
- Word Break II 求把字符串拆分为字典里的单词的所有方案 @LeetCode
- JCIP_4_01_扩展现有安全类_客户端加锁
- 今日作息及食谱(8.13)
- Changing the Cordova app icon
- 如果是作为客户端的HTTP+JSON接口工程,没有JSP等view视图的情况下,使用Jersery框架开发绝对是第一选择。而在基于Spring3 MVC的架构下,对HTTP+JSON的返回类型也有很好
- Sublime Text 2 Error trying to parse settings
- 使用PhoneGap Build 将web applications打包成native mobile applications
- 编写一个标准strcpy函数
- 如何构建优质代码
- 最完整最简洁的JavaScript基础教程