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

java并发编程实战-第3章-对象的共享

 
阅读更多

java并发编程实战-第3章-对象的共享

如何共享和发布对象,使其能符合第2章所讨论的多个线程下的安全性访问。2-3章是第4章构建线程安全类

 

和通过java.util.concurrent类库来构建并发应用程序的重要基础

 

同步除了实现原子性操作外,另一个重要方面内存可见性

 

 

3.1可见性

 

  In order to ensure visibility of memory writes across threads, you must use synchronization.

 

  public class NoVisibility {

    private static boolean ready;

    private static int number;

 

    private static class ReaderThread extends Thread {

        public void run() {

            while (!ready)

                Thread.yield();

            System.out.println(number);

        }

    }

 

    public static void main(String[] args) {

        new ReaderThread().start();

        number = 42;

        ready = true;

    }

}

 

 

在没有同步的情况下,无法保证主线程写入的值对读线程是可见的(虽然如上代码测试几次可能都会输出42

 

 

在没有同步的情况下,编译器、处理器以及运行时都可能对执行顺序做调整(重排序)

 

3.1.1 失效数据

 

NoVisibility 可能产生失效数据,可能输出错误的结果、可能引起死循环、意料外的异常、被破坏的数据

 

结构等等

 

3.1.2 非原子的64位操作

 

   对于64位的long、double操作。jvm 允许拆分成2个32位的操作。所以在多个线程的读写下即使不考虑数

 

据失效、也是不安全的。除非使用volatile声明或者用锁保护

   

3.1.3 加锁与可见性

          Locking is not just about mutual exclusion; it is also about memory visibility

 

3.1.4 volatile

      When a field is declared volatile, the compiler and runtime are put on notice that this 

 

variable is shared and that operations on it should not be reordered with other memory 

 

operations.

      Volatile variables are not cached in registers or in caches where they are hidden from 

 

other processors, so a read of a volatile variable always returns the most recent write by any 

 

thread

 

    即:1、不重排序 2、不缓存在寄存器或其他处理器不可见的地方

    

    

    volatile只能保证可见性,但不保证++count 的原子性。(原子变量提供了读-写-改的原子操作,通常

 

是一种更好的volatile变量)

 

   You can use volatile variables only when all the following criteria are met:(使用volatiel

 

,以下3个条件都要买足)

 

Writes to the variable do not depend on its current value, or you can 

 

ensure that only a single thread ever updates the value;

 

The variable does not participate in invariants with other state 

 

variables; and

 

Locking is not required for any other reason while the variable is 

 

being accessed.

    

    

    适用场景:

     1、作为状态标志

     volatile boolean asleep;

      ...

    while (!asleep)

        countSomeSheep();

        

3.2 发布和逸出

    发布:使对象在当前代码之外仍旧可用。比如存储对象的应用使其可以别的代码可以访问、通过非私有

 

方法返回、将引用传递给其他类的方法

    逸出:An object that is published when it should not have been is said to have escaped.

    

    逸出例子:

    例子1:共有静态的变量

   Listing 3.5. Publishing an Object.

public static Set<Secret> knownSecrets;

 

public void initialize() {

   knownSecrets = new HashSet<Secret>();

}

 

    如上共有静态的变量 knownSecrets,就是在没有initialize()完成,其它线程也能访问

    

    例子2:使内部的可变状态逸出

    class UnsafeStates {

    private String[] states = new String[] {

        "AK", "AL" ...

    };

    public String[] getStates() { return states; }

    }

   

    

    例子3:在public构造函数中发布内部类(发布的EventListener含有ThisEscape的this的隐式引用,但

 

ThisEscape确没有构造完成)

    public class ThisEscape {

    public ThisEscape(EventSource source) {

        source.registerListener(

            new EventListener() {

                public void onEvent(Event e) {

                    doSomething(e);

                }

            });

     }

   }

   

   需要当且仅当构造函数返回时,对象才处于可预测的和一致性状态

   所以,可以如下正确的发布:

   使用工厂方法防止this引用在构造过程中逸出

   

  public class SafeListener {

   private final EventListener listener;

 

   private SafeListener() {

       listener = new EventListener() {

           public void onEvent(Event e) {

               doSomething(e);

           }

       };

   }

 

   public static SafeListener newInstance(EventSource source) {

       SafeListener safe = new SafeListener();

       source.registerListener(safe.listener);

       return safe;

   }

}

 

 

3.3 线程封闭

    

    如果仅在单线程里访问数据,则不需要同步。

    应用例子:

    swing中大量使用线程封闭技术,   swing常见错误,其他线程使用了该被封闭的对象

    jdbc的Connection对象,web服务器的请求线程从连接池中获取一个connection对象,直到使用完后返

 

回给连接池。在此期间,不会把connection分配给其他线程

    ThreadLocal :struts2等框架,把请求参数通过ThreadLocal放在封闭在自己线程中

    

    方式有Ad-hoc、栈封闭、和ThreadLocal

    

    (5.3.2 的串行线程封闭是否属于Ad-hoc呢)

    

3.3.1 Ad-hoc 线程封闭(Ad-hoc拉丁语 for this 。专门的、特别设定的)

     封闭的职责完全由程序来负责,很脆弱

3.3.2 栈封闭

3.3.3 ThreadLocal类

 

      例子:

       private static ThreadLocal<Connection> connectionHolder

   = new ThreadLocal<Connection>() {

       public Connection initialValue() {

           return DriverManager.getConnection(DB_URL);

       }

   };

 

public static Connection getConnection() {

   return connectionHolder.get();

}

 

   

         

         

         

      可以看成把ThreadLocal(T)看成Map<Thread,T>,但不仅如此,提供了当线程停止后,T会被作为垃

 

圾回收

      应用程序框架大量使用ThreadLocal。J2EE容器需要将一个事务上下文( Transaction Context )与

 

某个执行的线程关联起来

      开发人员经常滥用ThreadLocal ,ThreadLocal 类似全局变量,它能降低代码的重用性。引入耦合。

 

操作要额外小心

      

      扩展:

      spring DAO模板等底层技术,ThreadLocal是必须攻克的

      

      

      

3.4 不变性

    3.4.1 Final域

    3.4.2 示例:使用Volatile类型发布不可变对象

3.5 安全发布

 

   Immutable objects can be used safely by any thread without additional synchronization, even 

 

when synchronization is not used to publish them.

   

3.5.3 安全发布常用模式

      可变对象必须通过安全的方式发布的,发布的

     To publish an object safely, both the reference to the object and the object's state must 

 

be made visible to other threads at the same time. A properly constructed object can be safely 

 

published by:

 

Initializing an object reference from a static initializer;(

怎么理解?

public static Holder holder = new Holder(42);

Static initializers are executed by the JVM at class initialization 

 

time; because of internal synchronization in the JVM, this mechanism is guaranteed to safely 

 

publish any objects initialized in this way [JLS 12.4.2].

      )

 

Storing a reference to it into a volatile field or AtomicReference;

 

Storing a reference to it into a final field of a properly constructed 

 

object; or

 

Storing a reference to it into a field that is properly guarded by a 

 

lock.

 

 

3.5.4 事实不可变对象

      技术上可变,事实上不可变

      

3.5.5  可变对象

 

The publication requirements for an object depend on its mutability:

 

Immutable objects can be published through any mechanism;

 

Effectively immutable objects must be safely published;

 

Mutable objects must be safely published, and must be either 

 

threadsafe or guarded by a lock(3.5.3介绍的安全发布模式)

3.5.6  安全的共享对象,即最后如下总结

 

 

总结:

  

  The most useful policies for using and sharing objects in a concurrent program are:

 

1、线程封闭 Thread-confined. A thread-confined object is owned exclusively by and 

 

confined to one thread, and can be modifled by its owning thread.

2、只读共享 Shared read-only. A shared read-only object can be accessed concurrently 

 

by multiple threads without additional synchronization, but cannot be modified by any thread. 

 

Shared read-only objects include immutable and effectively immutable objects.

3、线程安全的对象的共享 Shared thread-safe. A thread-safe object performs 

 

synchronization internally, so multiple threads can freely access it through its public 

 

interface without further synchronization.

4、保护对象 Guarded. A guarded object can be accessed only with a specific lock held. 

 

Guarded objects include those that are encapsulated within other thread-safe objects and 

 

published objects that are known to be guarded by a specific lock.

 

 

 

 

 

 

0
1
分享到:
评论

相关推荐

    Java 并发编程实战

    第3章 对象的共享 3.1 可见性 3.1.1 失效数据 3.1.2 非原子的64位操作 3.1.3 加锁与可见性 3.1.4 Volatile变量 3.2 发布与逸出 3.3 线程封闭 3.3.1 Ad-hoc线程封闭 3.3.2 栈封闭 3.3.3 ThreadLocal类 3.4...

    Java并发编程实践.pdf

    ### Java并发编程实践 #### 一、并发编程基础 ##### 1.1 并发与并行的区别 在Java并发编程中,首先需要理解“并发”(Concurrency)和“并行”(Parallelism)的区别。“并发”指的是多个任务在同一时间段内交替...

    Java并发编程实践 PDF 高清版

    第3章 共享对象 3.1 可见性 3.2 发布和逸出 3.3 线程封闭 3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 ...

    Java并发编程实战1

    《Java并发编程实战1》这本书深入探讨了Java平台上的并发编程技术。本书分为四个部分,旨在帮助读者理解和掌握如何在实际应用中有效地利用多线程。 第一部分的基础知识介绍了线程的基本概念。线程是程序执行的最小...

    java并发编程实践笔记

    ### Java并发编程实践笔记知识点详解 #### 一、保证线程安全的方法 1. **不要跨线程访问共享变量:** 当多个线程共享某个变量时,若其中一个线程修改了该变量,其他线程若没有正确同步,则可能读取到错误的数据。...

    高并发编程实战1,2,3阶段

    ### 高并发编程实战1,2,3阶段 #### 知识点概览 本系列教程分为三个阶段,旨在帮助开发者全面理解并掌握高并发编程技术。通过理论讲解与实战演练相结合的方式,深入剖析了多线程编程的核心原理及其在实际项目中的...

    汪文君JAVA多线程编程实战(完整不加密)

    本书还涉及到了Java并发工具类,如Semaphore信号量、CyclicBarrier栅栏、CountDownLatch倒计时器等,这些都是Java并发编程中的重要工具,可以帮助开发者更精细地控制线程执行。另外,书中还会介绍如何使用Future和...

    Java并发编程实践.rar

    第三章:共享数据与线程安全 这一章重点讲解了线程不安全的问题,如数据竞争、死锁、活锁和饥饿。并详细阐述了Java中的线程安全类,如Atomic类、synchronized关键字的用法,以及 volatile 关键字的作用。 第四章:...

    java 并发编程的艺术

    第3章详细介绍了这一主题,解开了Java内存模型的神秘面纱,帮助程序员更好地理解内存可见性问题及其解决方案。此外,书中还讨论了volatile关键字的实现原理,这是理解内存模型中不可忽视的一部分。 多线程编程是...

    JAVA开发实战经典-课后习题答案-李兴华.pdf

    - **多线程**: 原生支持多线程,简化了并发编程。 - **安全性**: Java设计时考虑到了安全性,例如数组边界检查等。 - **可移植性**: 可以在不同平台运行,提供跨平台的能力。 通过上述知识点的总结,可以了解到Java...

    并发相关书籍整理 高质量

    3. 《Java并发编程实战(中文版)》:这本书以实战为导向,提供了大量实例来帮助读者理解和掌握并发编程。内容可能涉及线程通信、并发控制、并发异常处理,以及如何在实际项目中避免并发问题。 4. 《Java多线程编程...

    java网络编程

    在本资料中,《Java网络编程》第三版提供了深入浅出的讲解,旨在帮助开发者提升对这一领域的理解。 1. **基础概念**: - **网络模型**:Java网络编程基于OSI七层模型和TCP/IP四层模型。理解这些模型有助于理解网络...

    实战Java高并发程序设计(第2版)PPT模板.pptx

    《实战Java高并发程序设计(第2版)》是一份深度剖析Java并发编程的PPT教程,涵盖了从基础到高级的多个重要知识点。以下是其中的关键内容概览: 1. **走入并行世界**: - **并行计算的前景与挑战**:随着硬件的...

    Java_9_Concurrency_Cookbook_-_Second_Edition.pdf

    #### 标题:Java 9 并发编程实战指南 —— 第二版 此书名为《Java 9 并发编程实战指南 —— 第二版》(以下简称“本书”),由 Javier Fernández González 著作,于2017年4月出版。本书旨在帮助读者掌握Java 9中...

    Java程序设计教程-电子教案

    Java程序设计教程是一套专为学习者设计的电子教案,旨在帮助初学者和进阶者掌握Java编程语言的核心概念和实战技巧。这份教程涵盖了Java语言的各个方面,包括基础语法、面向对象编程、异常处理、输入输出、集合框架、...

    java线程实战手册

    《Java线程实战手册》是Java并发编程领域的一份重要参考资料,主要针对Java开发者,旨在帮助他们深入理解和熟练掌握Java中的多线程技术。虽然这里只提供了第一章的内容,但这一章通常会涵盖基础理论和核心概念,对于...

    Java分布式实战指南.pdf

    第三方云数据库为数据存储提供可靠的保障,而腾讯云存储则负责文件的存储。 在项目构建过程中,书中给出了详细的模块划分。例如,创建了gxa-parent作为公共父工程,gxa-basics包含分布式基础设施相关组件,如XXL-...

    java高级编程第四章实用类

    - **线程安全**:如果实用类的方法处理的是共享资源,那么它们需要确保线程安全,以避免并发问题。 2. **常见的实用类** - **java.lang.Math**:提供数学运算,如平方根、最大值、最小值等。 - **java.util....

    java网络编程技术与实践(源程序第15章)

    本章节聚焦于"Java网络编程技术与实践",特别是第15章,这是一份包含源程序的深入学习资源。由于文件大小超过80兆,作者为了减小文件体积,不得不删除了`lib`目录下的所有`jar`库。尽管如此,我们依然可以从剩下的`...

Global site tag (gtag.js) - Google Analytics