`

《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并发编程实战

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

    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并发编程实战》读书笔记-第4章-对象的组合

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

    Java并发编程实战2019.zip

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

    Java虚拟机并发编程.pdf

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

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

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

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

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

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

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

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

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

Global site tag (gtag.js) - Google Analytics