`

《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并发编程实践高清pdf及源码

    《Java并发编程实践》是一本深入探讨Java多线程编程的经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和David Holmes等专家共同编写。这本书全面介绍了Java平台上的并发编程技术,是Java开发...

    java并发编程

    Java并发编程是Java开发者必须掌握的关键技能之一,它涉及到如何在多线程环境中高效、安全地执行程序。并发编程能够充分利用多核处理器的计算能力,提高应用程序的响应速度和整体性能。《Java编程并发实战》这本书是...

    Java 并发编程实战

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

    java并发编程实践的.pptx

    根据提供的文档内容,我们可以归纳并深入探讨Java并发编程的一些核心概念和原理,这些知识点对于理解和实践Java并发编程至关重要。 ### JVM内存模型 JVM内存模型是理解Java并发的基础。主要包含以下几个部分: ##...

    Java并发编程实践 PDF 高清版

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

    Java虚拟机并发编程.pdf

    在Java并发编程中,关键字`volatile`扮演着关键角色。它确保了共享变量在多线程环境中的可见性,防止了数据的不一致。当一个变量被声明为`volatile`时,任何线程对它的修改都会立即反映到其他线程中,消除了由于缓存...

    java并发编程之同步器代码示例

    Java并发编程之同步器代码示例 Java并发编程中,同步器是一种使线程能够等待另一个线程的对象,允许它们协调动作。常用的同步器有CountDownLatch、Semaphore、Barrier和Exchanger队列同步器等。...

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

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

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

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

    Java编程模式与范例:基础开发技巧.rar

    《Java编程模式与范例:基础开发技巧》是一本深入探讨Java编程的著作,它涵盖了各种编程模式和实例,旨在帮助开发者提升技能并熟练掌握Java编程的基础技巧。在这个压缩包中,除了书籍的主文件外,还包含了辅助阅读...

    【小家java】JUC并发编程之:虚假唤醒以及推荐的解决方案.docx

    在Java并发编程中,尤其是在处理多线程同步时,一个重要的概念是“虚假唤醒”(Spurious Wakeup)。这是一种较为罕见的现象,但在实际开发过程中仍然值得高度关注。虚假唤醒指的是,在没有其他线程调用`notify()`...

    java并发编程实践(英文).docx

    Java并发编程实践是一本深入探讨Java多线程编程的经典书籍,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer和David Holmes以及Doug Lea共同撰写,由Addison-Wesley Professional出版社出版,书号为ISBN ...

    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并发工具包对并发编程的优化.zip

    1. **Executor框架**:这是Java并发编程的核心,它定义了一个任务提交的接口Executor,而不是直接使用Thread。ExecutorService接口扩展了Executor,提供了管理和控制线程池的方法,如submit()、shutdown()和...

    java 并发编程实践 001

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

Global site tag (gtag.js) - Google Analytics