知识大全 多线程编程您不知道的5件事

Posted 变量

篇首语:欠伸展肢体,吟咏心自愉。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 多线程编程您不知道的5件事相关的知识,希望对你有一定的参考价值。

    多线程编程向来不容易 但很少有 Java? 开发人员能够忽视多线程编程和支持它的 Java 平台库我们临时学习线程 在需要时向我们的工具箱添加新的技巧和技术 以这种方式构建和运行适当的应用程序是可行的 但是您可以做的不止这些 理解 Java 编译器的线程处理特性和 JVM 将有助于您编写更高效 性能更好的 Java 代码         在这篇文章中 我将通过同步方法 volatile 变量和原子类介绍多线程编程的一些更隐晦的方面 我的讨论特别关注于这些构建如何与 JVM 和 Java 编译器交互 以及不同的交互如何影响 Java 应用程序的性能         同步方法或同步代码块?        您可能偶尔会思考是否要同步化这个方法调用 还是只同步化该方法的线程安全子集 在这些情况下 知道 Java 编译器何时将源代码转化为字节代码会很有用 它处理同步方法和同步代码块的方式完全不同         当 JVM 执行一个同步方法时 执行中的线程识别该方法的 method_info 结构是否有 ACC_SYNCHRONIZED 标记设置 然后它自动获取对象的锁 调用方法 最后释放锁 如果有异常发生 线程自动释放锁         另一方面 同步化一个方法块会越过 JVM 对获取对象锁和异常处理的内置支持 要求以字节代码显式写入功能 如果您使用同步方法读取一个方法的字节代码 就会看到有十几个额外的操作用于管理这个功能 清单 展示用于生成同步方法和同步代码块的调用         清单 两种同步化方法   

  

     synchronizedMethodGet() 方法生成以下字节代码    

  

     这里是来自 synchronizedBlockGet() 方法的字节代码    

  

     创建同步代码块产生了 行的字节码 而创建同步方法仅产生了 行         ThreadLocal 变量        如果您想为一个类的所有实例维持一个变量的实例 将会用到静态类成员变量 如果您想以线程为单位维持一个变量的实例 将会用到线程局部变量 ThreadLocal 变量与常规变量的不同之处在于 每个线程都有其各自初始化的变量实例 这通过 get() 或 set() 方法予以评估         比方说您在开发一个多线程代码跟踪器 其目标是通过您的代码惟一标识每个线程的路径 挑战在于 您需要跨多个线程协调多个类中的多个方法 如果没有 ThreadLocal 这会是一个复杂的问题 当一个线程开始执行时 它需要生成一个惟一的令牌来在跟踪器中识别它 然后将这个惟一的令牌传递给跟踪中的每个方法         使用 ThreadLocal 事情就变得简单多了 线程在开始执行时初始化线程局部变量 然后通过每个类的每个方法访问它 保证变量将仅为当前执行的线程托管跟踪信息 在执行完成之后 线程可以将其特定的踪迹传递给一个负责维护所有跟踪的管理对象         当您需要以线程为单位存储变量实例时 使用 ThreadLocal 很有意义         Volatile 变量        我估计 大约有一半的 Java 开发人员知道 Java 语言包含 volatile 关键字 当然 其中只有 % 知道它的确切含义 有更少的人知道如何有效使用它 简言之 使用 volatile 关键字识别一个变量 意味着这个变量的值会被不同的线程修改 要完全理解 volatile 关键字的作用 首先应当理解线程如何处理非易失性变量         为了提高性能 Java 语言规范允许 JRE 在引用变量的每个线程中维护该变量的一个本地副本 您可以将变量的这些 线程局部 副本看作是与缓存类似 在每次线程需要访问变量的值时帮助它避免检查主存储器         不过看看在下面场景中会发生什么 两个线程启动 第一个线程将变量 A 读取为 第二个线程将变量 A 读取为 如果变量 A 从 变为 第一个线程将不会知道这个变化 因此会拥有错误的变量 A 的值 但是如果将变量 A 标记为 volatile 那么不管线程何时读取 A 的值 它都会回头查阅 A 的原版拷贝并读取当前值         如果应用程序中的变量将不发生变化 那么一个线程局部缓存比较行得通 不然 知道 volatile 关键字能为您做什么会很有帮助         易失性变量与同步化        如果一个变量被声明为 volatile 这意味着它预计会由多个线程修改 当然 您会希望 JRE 会为易失性变量施加某种形式的同步 幸运的是 JRE 在访问易失性变量时确实隐式地提供同步 但是有一条重要提醒 读取易失性变量是同步的 写入易失性变量也是同步的 但非原子操作不同步         这表示下面的代码不是线程安全的         myVolatileVar++;        上一条语句也可写成    

  

     换言之 如果一个易失性变量得到更新 这样其值就会在底层被读取 修改并分配一个新值 结果将是一个在两个同步操作之间执行的非线程安全操作 然后您可以决定是使用同步化还是依赖于 JRE 的支持来自动同步易失性变量 更好的方法取决于您的用例 如果分配给易失性变量的值取决于当前值(比如在一个递增操作期间) 要想该操作是线程安全的 那么您必须使用同步化         原子字段更新程序        在一个多线程环境中递增或递减一个原语类型时 使用在 ncurrent atomic 包中找到的其中一个新原子类比编写自己的同步代码块要好得多 原子类确保某些操作以线程安全方式被执行 比如递增和递减一个值 更新一个值 添加一个值 原子类列表包括 AtomicInteger AtomicBoolean AtomicLong AtomicIntegerArray 等等         使用原子类的难题在于 所有类操作 包括 get set 和一系列 get set 操作是以原子态呈现的 这表示 不修改原子变量值的 read 和 write 操作是同步的 不仅仅是重要的 read update write 操作 如果您希望对同步代码的部署进行更多细粒度控制 那么解决方案就是使用一个原子字段更新程序         使用原子更新        像 AtomicIntegerFieldUpdater AtomicLongFieldUpdater 和 AtomicReferenceFieldUpdater 之类的原子字段更新程序基本上是应用于易失性字段的封装器 Java 类库在内部使用它们 虽然它们没有在应用程序代码中得到广泛使用 但是也没有不能使用它们的理由         清单 展示一个有关类的示例 该类使用原子更新来更改某人正在读取的书目         清单 Book 类   

  

     Book 类仅是一个 POJO(Java 原生类对象) 拥有一个单一字段 name         清单 MyObject 类   

  

     正如您所期望的 清单 中的 MyObject 类通过 get 和 set 方法公开其 whatAmIReading 属性 但是 set 方法所做的有点不同 它不仅仅将其内部 Book 引用分配给指定的 Book(这将使用 清单 中注释出的代码来完成) 而是使用一个 AtomicReferenceFieldUpdater         AtomicReferenceFieldUpdater        AtomicReferenceFieldUpdater 的 Javadoc 将其定义为         对指定类的指定易失性引用字段启用原子更新的一个基于映像的实用程序 该类旨在用于这样的一个原子数据结构中 即同一节点的若干引用字段独立地得到原子更新         在 清单 中 AtomicReferenceFieldUpdater 由一个对其静态 newUpdater 方法的调用创建 该方法接受三个参数         包含字段的对象的类(在本例中为 MyObject)        将得到原子更新的对象的类(在本例中是 Book)        将经过原子更新的字段的名称        这里真正的价值在于 getWhatImReading 方法未经任何形式的同步便被执行 而 setWhatImReading 是作为一个原子操作执行的         清单 展示如何使用 setWhatImReading() 方法并断定值的变动是正确的         清单 演习原子更新的测试用例   

  

     结束语        多线程编程永远充满了挑战 但是随着 Java 平台的演变 它获得了简化一些多线程编程任务的支持 在本文中 我讨论了关于在 Java 平台上编写多线程应用程序您可能不知道的 件事 包括同步化方法与同步化代码块之间的不同 为每个线程存储运用 ThreadLocal 变量的价值 被广泛误解的 volatile 关键字(包括依赖于 volatile 满足同步化需求的危险) 以及对原子类的错杂之处的一个简要介绍 cha138/Article/program/Java/gj/201311/27308

相关参考

知识大全 Java 5.0多线程编程

Java5.0多线程编程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java自年面世以来得到

知识大全 Java多线程编程基础之线程和多线程

Java多线程编程基础之线程和多线程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  随着计算机技

知识大全 超线程多核心下Java多线程编程分析

超线程多核心下Java多线程编程分析  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一Java环

知识大全 超线程多核心下Java多线程编程技术分析[4]

超线程多核心下Java多线程编程技术分析[4]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb

知识大全 超线程多核心下Java多线程编程技术分析[3]

超线程多核心下Java多线程编程技术分析[3]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb

知识大全 超线程多核心下Java多线程编程技术分析[1]

超线程多核心下Java多线程编程技术分析[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb

知识大全 超线程多核心下Java多线程编程技术分析[2]

超线程多核心下Java多线程编程技术分析[2]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb

知识大全 Java多线程编程基础之线程对象

Java多线程编程基础之线程对象  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &nbs

知识大全 Java多线程编程

Java多线程编程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作者natrium    一理

知识大全 Linux下的多线程编程

Linux下的多线程编程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  引言    线程(thr