`
zhouchaofei2010
  • 浏览: 1084960 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java并发编程实战-第4章-对象的组合

 
阅读更多

java并发编程实战-第4章-对象的组合

 

(重点:组合模式)

 

4.3.5 重点:理解发布状态可变的车辆追踪器

 

p58 理解脚注:  如果将拷贝构造函数实现为this(p.x,p.y),那么会产生竞态 条件,而私有构造函数则可以避免这种竞态条件.这是私有构造函数捕获模式的一个实例

 

 

测试类

public class SafePointMain {

public static void main(String[] args) throws Exception {

    final SafePoint originalSafePoint = new SafePoint(1,1);

 

    //One Thread is trying to change this SafePoint

    new Thread(new Runnable() {

        @Override

        public void run() {

            originalSafePoint.setXY(2, 2);

            System.out.println("Original : " + originalSafePoint.toString());

        }

    }).start();

 

    //The other Thread is trying to create a copy. The copy, depending on the JVM, MUST be either (1,1) or (2,2)

    //depending on which Thread starts first, but it can not be (1,2) or (2,1) for example.

    new Thread(new Runnable() {

        @Override

        public void run() {

            SafePoint copySafePoint = new SafePoint(originalSafePoint);

            System.out.println("Copy : " + copySafePoint.toString());

        }

    }).start();

}

}

安全类:使用私有构造函数

 

@ThreadSafe

public class SafePoint {

    @GuardedBy("this") private int x, y;

 

    private SafePoint(int[] a) { this(a[0], a[1]); }

 

    public SafePoint(SafePoint p) { this(p.get()); }

 

    public SafePoint(int x, int y) {

        this.x = x;

        this.y = y;

    }

 

    public synchronized int[] get() {

        return new int[] { x, y };

    }

 

    public synchronized void set(int x, int y) {

        this.x = x;

        this.y = y;

    }

   

@Override

public String toString() {

return "("+x+","+y+")";

}

}

 

用SafePointMain测试的结果(真确)

 

 

如果不用私有构造函数,而直接使用下面类SafePoint2,

 

class SafePoint2 {

    private int x;

    private int y;

 

    public SafePoint(int x, int y){

        this.x = x;

        this.y = y;

    }

 

    public SafePoint(SafePoint safePoint){

        this(safePoint.x, safePoint.y);

    }

 

    public synchronized int[] getXY(){

        return new int[]{x,y};

    }

 

    public synchronized void setXY(int x, int y){

        this.x = x;

        //Simulate some resource intensive work that starts EXACTLY at this point, causing a small delay

        try {

            Thread.sleep(10 * 100);

        } catch (InterruptedException e) {

         e.printStackTrace();

        }

        this.y = y;

    }

 

    public String toString(){

      return Objects.toStringHelper(this.getClass()).add("X", x).add("Y", y).toString();

    }

}

 

则测试结果,:

 

Copy : (2,1)

Original : (2,2)

 

 

本质上,是写(setXY) 与读(构造函数中的 this(safePoint.x, safePoint.y);)不同步造成的,而构造函数不不能使用同步机制的

 

但是getXY方法是安全的,所以构造一个接受getXY参数的构造函数

 

private SafePoint(int [] xy){

    this(xy[0], xy[1]);

}

 

And then, the actual invokation:

 

public  SafePoint (SafePoint safePoint){

    this(safePoint.getXY());

}

Notice that the constructor is private, this is because we do not want to expose yet another public constructor and think again about the invariants of the class, thus we make it private - and only we can invoke it.

 

具体参考stackoverflow上Eugene的精彩的解答:http://stackoverflow.com/questions/12028925/private-constructor-to-avoid-race-condition/12029346

 

 

 

 

 

 

4.1 设计线程安全的类

    三个基本要素

    变量、约束状态变量的不变性条件、建立对象状态并发访问的管理策略

    同步策略定义了如何在不违背对象的不边条件或者后验条件的情况下对其状态的访问进行协同。

    同步策略规定了如何将不变性、线程封闭、加锁机制等结合起来维护线程的安全性。规定了哪些变量由哪写所保护,为了开发人员可以对这个类进行分析与维护,还得把同步策略写成文档

    

4.1.1 收集同步需求

      比如,

      Count类中的变量的long的取值范围、不能为负数

      当前状态时17,那么下一个状态必须是18的后验条件等

      

      例子:

      @ThreadSafe

public final class Counter {

   @GuardedBy("this")  private long value = 0;

 

   public synchronized  long getValue() {

       return value;

   }

   public  synchronized  long increment() {

       if (value == Long.MAX_VALUE)

           throw new IllegalStateException("counter overflow");

       return ++value;

   }

}

 

 

      

4.1.2 依赖状态的操作

    

    For example, you cannot remove an item from an empty queue; a queue must be in the "nonempty" state before you can remove an element.

    

    

4.1.3 状态所有权

 

     比如,servlet中的ServletContext中的对象通过setAttribut和getAttribut不需要同步,但其状态所有权属于应用程序,由应用程序来控制同步

 

4.2 实例封闭

    

    将数据封装在对象内部,对象的方位只限制在对象的方法上,从而更容易确保线程在访问数据时总能持有争取的锁

4.2.1  java监视器模式

 

     即:synchronized ,Vector 和Hashtable

     

4.2.2 示例:车辆追踪

      

     在车辆很多的情况下,如果需要一致的快照则是优点。如果需要实时的最新信息,则是缺点

     

4.3 线程安全性的委托

 

4.3.1 示例:基于委托的车辆追踪器

 

     使用不变的point类

     

     将线程安全委托给ConcurrentHashMap

     

     

4.3.2 独立的状态变量

     例子:VisualComponent keyListeners 和 mouseListeners 中两个链表都是线程安全的,且没有耦合。所以VisualComponent把安全委托给两个安全的链表是可以的

 

4.3.3 当委托无效时  

     例子:NumberRange 中  AtomicInteger lower 和  AtomicInteger upper,虽然是线程安全的类。但彼此有耦合关系,此时需要加锁机制处理 

 

4.3.4 发布底层的状态变量 

      如果Counter类中,value有约束不能为负数,发布value则会这个类出错

     VisualComponent中keyListeners 和 mouseListeners 时安全的,是可以发布的

      

 

4.3.5 示例:发布状态可变的车辆追踪器

     (已在开头重点描述)

     

     

 

4.4 在现有安全类中添加功能

   例如,给一个安全的列表添加原子操作(put-if-Absent)

   方法1:最安全的方式是修改源代码,但这通常无法做到    

   方法2:扩张extends,但比直接修改源代码脆弱。因为同步策略实现被分布到多个单独维护的线程中

   方法3:扩展类的功能(4.4.1 客户端加锁例子)

   方法4:组合(更好的方式,4.4.2介绍)

   

4.4.1 客户端加锁机制

  对于 被Collections.synchronizedLis的ArrayList,以上方法都不行,以为客户端并不知道ArrayList的class,第三种方法,扩展类的功能,放在一个辅助类中

  

   @NotThreadSafe

public class ListHelper<E> {

   public List<E> list =

       Collections.synchronizedList(new ArrayList<E>());

   ...

   public synchronized boolean putIfAbsent(E x) {

       boolean absent = !list.contains(x);

       if (absent)

           list.add(x);

       return absent;

   }

}

但是如上方法,在错误的锁上进行了同步,应为

 

@ThreadSafe

public class ListHelper<E> {

   public List<E> list =

       Collections.synchronizedList(new ArrayList<E>());

   ...

   public boolean putIfAbsent(E x) {

       synchronized (list)  {

           boolean absent = !list.contains(x);

           if (absent)

               list.add(x);

           return absent;

       }

   }

}

 

 

4.4.2 Composition

 

Listing 4.16. Implementing Put-if-absent Using Composition.

@ThreadSafe

public class ImprovedList<T> implements List<T> {

    private final List<T> list;

 

    public ImprovedList(List<T> list) { this.list = list; }

 

    public synchronized boolean putIfAbsent(T x) {

        boolean contains = list.contains(x);

        if (contains)

            list.add(x);

        return !contains;

    }

 

    public synchronized void clear() { list.clear(); }

    // ... similarly delegate other List methods

}

 

 

4.5 将同步策略文档化

     Document a class's thread safety guarantees for its clients; 向客户端说明类的线程安全性保证的

     document its synchonization policy for its maintainers. 向维护人员提供同步策略

     

 

   

分享到:
评论

相关推荐

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

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

    Java并发编程实战

    第4章 对象的组合 4.1 设计线程安全的类 4.1.1 收集同步需求 4.1.2 依赖状态的操作 4.1.3 状态的所有权 4.2 实例封闭 4.2.1 Java监视器模式 4.2.2 示例:车辆追踪 4.3 线程安全性的委托 4.3.1 示例:基于...

    Java并发编程实战2019.zip

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

    Java 并发编程实战

    第4章 对象的组合 4.1 设计线程安全的类 4.1.1 收集同步需求 4.1.2 依赖状态的操作 4.1.3 状态的所有权 4.2 实例封闭 4.2.1 Java监视器模式 4.2.2 示例:车辆追踪 4.3 线程安全性的委托 4.3.1 示例:基于...

    Java 7并发编程实战手册

    《Java 7并发编程实战手册》是Java 7并发编程的实战指南,介绍了Java 7并发API中大部分重要而有用的机制。全书分为9章,涵盖了线程管理、线程同步、线程执行器、Fork/Join框架、并发集合、定制并发类、测试并发应用...

    Java并发编程实践 PDF 高清版

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

    龙果 java并发编程原理实战

    龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...

    《Java并发编程的艺术》源代码

    第1章介绍Java并发编程的挑战,向读者说明进入并发编程的世界可能会遇到哪些问题,以及如何解决。 第2章介绍Java并发编程的底层实现原理,介绍在CPU和JVM这个层面是如何帮助Java实现并发编程的。 第3章介绍深入介绍...

    joeylv#joscrapy#【Java并发编程实战】-----AQS(四):CLH同步队列1

    在线程获取锁时会调用AQS的acquire()方法,该方法第一次尝试获取锁如果失败,会将该线程加入到CLH队列中:public final void acqui

    汪文君高并发编程实战视频资源下载.txt

    │ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...

    Java并发编程实战(中文版)

    java并发编程(中文版,pdf格式),本书共16章,主要有四部分,第一部分:基础知识,第二部分:结构化并发应用程序,第三部分:活跃性、性能与测试,第四部分:高级主题。

    Java并发编程的艺术

    第1章介绍Java并发编程的挑战,会向读者说明可能会遇到哪些问题,以及如何解决。第2章Java并发编程的底层实现原理,从CPU和JVM2个层面剖析。第3章详细深入介绍了Java的内存模型。第4章从介绍多线程技术带来的好处...

    Java并发编程的艺术_非扫描

    第1章介绍Java并发编程的挑战,向读者说明进入并发编程的世界可能会遇到哪些问题,以及如何解决。第2章介绍Java并发编程的底层实现原理,介绍在CPU和JVM这个层面是如何帮助Java实现并发编程的。第3章介绍深入介绍了...

    Java 并发编程原理与实战视频

    java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个...

    汪文君高并发编程实战视频资源全集

    │ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...

    龙果java并发编程完整视频

    第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的...

    汪文君高并发编程实战视频 第三阶段

    高并发编程 汪文君高并发编程实战视频 第三阶段 百度网盘 ev4格式(没有破解、没有破解、没有破解)

Global site tag (gtag.js) - Google Analytics