`

《Java并发编程》之二:对象的组合

    博客分类:
  • Java
阅读更多

当对象下一个状态需要依赖当前状态时,这个操作必须是一个复合操作。并非所有操作都会在状态转换上施加限制,比如直接更新字段,以赋值形式,典型的就是javabean的get/set方法。

如果在一个不变性条件中包含多个变量,那么在执行任何访问相关变量的操作时候,都必须持有保护这些变量的锁。

 

下面的PersonSet说明了如何通过实例封闭与加锁机制使一个可变对象或者线程不安全对象成为一个线程安全对象:

@ThreadSafe
public class PersonSet {
    @GuardedBy("this")
    private final Set<Person> mySet = new HashSet<Person>();

    public synchronized void addPerson(Person p) {
        mySet.add(p);
    }

    public synchronized boolean containsPerson(Person p) {
        return mySet.contains(p);
    }

    interface Person {
    }
}

HashSet本身并不是线程安全的,但是由于它是一个私有成员变量,唯一可以访问mySet代码路径就是公共方法addPerson和containsPerson,但是这个两个方法都加了锁,所以会同步,因此是线程安全的。

 

一个基于监视器模式的车辆追踪示例:

 

@NotThreadSafe  
public class MutablePoint {  
    public int x, y;  
  
    public MutablePoint() {  
        x = 0;  
        y = 0;  
    }  
  
    public MutablePoint(MutablePoint p) {  
        this.x = p.x;  
        this.y = p.y;  
    }  
}
 MonitorVehicleTracker.java:
@ThreadSafe  
public class MonitorVehicleTracker {  
    @GuardedBy("this")  
    private final Map<String, MutablePoint> locations;  
  
    public MonitorVehicleTracker(Map<String, MutablePoint> locations) {  
        this.locations = deepCopy(locations);  
    }  
  
    public synchronized Map<String, MutablePoint> getLocations() {  
        return deepCopy(locations);  
    }  
  
    public synchronized MutablePoint getLocation(String id) {  
        MutablePoint loc = locations.get(id);  
        return loc == null ? null : new MutablePoint(loc);  
    }  
  
    public synchronized void setLocation(String id, int x, int y) {  
        MutablePoint loc = locations.get(id);  
        if (loc == null)  
            throw new IllegalArgumentException("No such ID: " + id);  
        loc.x = x;  
        loc.y = y;  
    }  
  
    private static Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> m) {  
        Map<String, MutablePoint> result = new HashMap<String, MutablePoint>();  
  
        for (String id : m.keySet())  
            result.put(id, new MutablePoint(m.get(id)));  
  
        return Collections.unmodifiableMap(result);  
    }  
} 
大多数组合对象都会存在:它们的状态变量之间存在某些不变形条件。比如下面的数值范围类NumberRange.java,最小值必须≤最大值:
public class NumberRange {  
    // INVARIANT: lower <= upper  
    private final AtomicInteger lower = new AtomicInteger(0);  
    private final AtomicInteger upper = new AtomicInteger(0);  
  
    public void setLower(int i) {  
        // Warning -- unsafe check-then-act  
        if (i > upper.get())  
            throw new IllegalArgumentException("can't set lower to " + i + " > upper");  
        lower.set(i);  
    }  
  
    public void setUpper(int i) {  
        // Warning -- unsafe check-then-act  
        if (i < lower.get())  
            throw new IllegalArgumentException("can't set upper to " + i + " < lower");  
        upper.set(i);  
    }  
  
    public boolean isInRange(int i) {  
        return (i >= lower.get() && i <= upper.get());  
    }  
}

 

如果某个类含有复合操作,例如NumberRange,那么仅靠委托并不足以实现线程安全性。也就是说,即便是每个实例域都是线程安全的,但是复合操作却不一定是线程安全的。  

 

如果一个类是由多个独立且线程安全的状态变量组成,并且在所有操作中都不包含无效状态转换,那么可以将线程安全性委托给底层的状态变量。 注意上面的无效状态转换,比如一个long类型的变量,它的值的改变有个约束就是不能大于Long.MAX值。  

 

本人博客已搬家,新地址为:http://yidao620c.github.io/

分享到:
评论

相关推荐

    Java并发编程实战

    第二部分 结构化并发应用程序 第6章 任务执行 6.1 在线程中执行任务 6.1.1 串行地执行任务 6.1.2 显式地为任务创建线程 6.1.3 无限制创建线程的不足 6.2 Executor框架 6.2.1 示例:基于Executor的Web服务器 ...

    JAVA 并发编程实战

    Java并发编程实战,本书从线程的基础知识,包括线程安全性,对象共享以及对象组合灯,到结构化并发编程,都提供了很详细的讲解。

    Java 并发编程实战

    第二部分 结构化并发应用程序 第6章 任务执行 6.1 在线程中执行任务 6.1.1 串行地执行任务 6.1.2 显式地为任务创建线程 6.1.3 无限制创建线程的不足 6.2 Executor框架 6.2.1 示例:基于Executor的Web服务器 ...

    Java并发编程实践 PDF 高清版

    本书的读者是那些具有一定Java编程经验的程序员、希望了解Java SE 5,6在线程技术上的改进和新特性的程序员,以及Java和并发编程的爱好者。 目录 代码清单 序 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的...

    《java并发编程实战》读书笔记-第4章-对象的组合

    《java并发编程实战》读书笔记-第3章-对象的共享,脑图形式,使用xmind8制作 包括线程安全类设计、实例封闭、线程安全性委托、现有线程安全类中添加功能和文档化同步策略等内容

    Java并发编程实战2019.zip

    Java并发编程实战,第1章 简介,第2章 线程安全性 第3章 对象的共享 第4章 对象的组合 第5章 基础构建模块 第6章 任务执行 第7章 取消与关闭 第8章 线程池的使用 第9章 图形用户界面应用程序 第10章 避免...

    Java并发编程实战-读书笔记

    《Java并发编程实战》个人读书笔记,非常详细: 1 简介 2 线程安全性 3 对象的共享 4 对象的组合 5 基础构建模块 6 任务执行 7 取消与关闭 8 线程池的使用 9 图形用户界面应用程序 10 避免活跃性危险 11 性能与可...

    JAVA并发编程实践-线程对象与组合对象-学习笔记

    使用java.util.concurrent类库构造安全的并发应用程序的基础。共享其实就是某一线程的数据改变对其它线程可见,否则就会出现脏数据。

    JAVA并发编程实践_中文版(1-16章全)_1/4

    第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和生产者一消费者模式 5.4 阻塞...

    Java并发编程(学习笔记).xmind

    Java并发编程 背景介绍 并发历史 必要性 进程 资源分配的最小单位 线程 CPU调度的最小单位 线程的优势 (1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 ...

    java 并发编程实践 001

    java 并发编程实践001 002 两个文件全部下载后 用 7z解压 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 线程的风险 1.4 线程无处不在 第1部分 基础 第2章 线程安全 2.1 什么是线程安全性 2.2 原子...

    Java并发编程part2

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

    Java并发编程实践part1

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

    天猫内部资料-Java并发编程

    对象类型: 对象地址原子读写,线程安全 并发读不可变状态,线程安全 并发读写可变状态,非线程线程 基本类型: int,char数值读写,线程安全 long,double高低位,非线程安全 i++等组合操作,非线程安全

    基础深化和提高-java函数式编程

    Java函数式编程是指利用函数式编程的思想和特性来开发Java应用程序。函数式编程强调将计算...函数式编程在Java中的应用可以带来许多好处,包括代码简洁、易于并发编程、函数复用性高等。另外,函数式编程也与并行计算

    JAVA_API1.6文档(中文)

    java.util.concurrent 在并发编程中很常用的实用工具类。 java.util.concurrent.atomic 类的小工具包,支持在单个变量上解除锁的线程安全编程。 java.util.concurrent.locks 为锁和等待条件提供一个框架的接口和类...

    C++编程思想(Thinking in C++)完美版pdf

    他是C++标准委员会拥有表决权的成员之一,曾经写过另五本面向对象编程书籍,发表过150篇以上的文章,是多本计算机杂志的专栏作家。Eckel开创Software Development Conference的C++、Java、Python等多项研讨活动。...

    Java 1.6 API 中文 New

    java.util.concurrent 在并发编程中很常用的实用工具类。 java.util.concurrent.atomic 类的小工具包,支持在单个变量上解除锁的线程安全编程。 java.util.concurrent.locks 为锁和等待条件提供一个框架的接口和类,...

Global site tag (gtag.js) - Google Analytics