`

Java 并发编程基础-共享对象

阅读更多

 

Java 并发编程基础 - 共享对象

 

目录

Java 并发编程基础 - 共享对象 ... 1

1.            可见性 ... 1

1.1过期数据 ... 2

1.2 非原子的 64位操作 ... 3

1.3 Volatile变量是有代价的 ... 3

2.            发布和逸出 ... 3

3.            线程封闭 ... 5

3.1      栈限制 ... 5

3.2      ThreadLocal 5

3.3      不可变性 ... 6

 

1. 可见性

在没有同步的情况下,编译器,处理器,运行时安排操作的执行顺序可能完全出人意料,在没有进行适当同步的多线程程序中,尝试推断哪些“必要”发生在内存中的动作是,你总是会判断错误。

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;

}

}

因为没有进行适当的同步, ready 的值为 true ,对读线程来说, ready 的值可能永远不可见,甚至 NoVisibility 可能会打印出 0. 因为早在对 number 赋值之前,主线程就已经写入 ready 并使之对读线程可见,这是一种“重排序 (Reordering) ”现象。

 

详见关于重排序的说明。

1.1 过期数据

当一个线程调用 set ,另外一个线程调用 get ,读线程和可能得到一个过期的数据:

@NotThreadSafe

Public class MutableInteger{

      Private int value;

      Public int get(){     return value;     }

      Public void set(int value){    this.value=value;   }

}

通过 Java 的同步机制,可以保证可见性,保证强的一致性(可以立即看到更新后的结果)

@ThreadSafe

Public class MutableInteger{

      Private int value;

      Public synchronized int get(){       return value;     }

      Public synchronized void set(int value){this.value=value;}

}

 

1.2 非原子的 64 位操作

Java 存储模型要求获取和存储操作都为原子的,但是对于非 volatile long double 变量, JVM 允许将 64 位的读或写划分为两个 32 位操作。如果读和写发生在不同的线程,这种情况读取了一个非 volatile 类型 long 就可能得到一个值的高 32 位和另一个值的低 32 位。

 

 

1.3 Volatile 变量是有代价的

现代处理器的发展,让 CPU 的处理能力得到了质的飞跃,这一切都与 cpu 的高速缓存有关系,这就是为什么 Java 内存模型里面,为什么各自线程有自己的工作内存的原因了,另外也由于直接操作主存,需要耗费更多的 CPU 时钟周期,但是如果存在线程安全问题, volatile 不会使用运行线程所在的 CPU 里面的缓存来读取和写输入, volatile 直接操作的是主存。因此实际上, volatile 为了保全可见性,也牺牲了很多性能。

 

 

2. 发布和逸出

发布 一个对象指的是使它能够被当前范围之外的代码所使用。比如讲一个引用存储到其他代码可以访问的地方,在一个非私有的方法中返回这个引用,也可以把它传递给其它的方法。

 

逸出 指的是一个对象在尚未准备好时就将他发布。

 

不正确的发布对象 - 范围逸出:任何一个调用者都可以修改他的内容,在下例中,数组逸出了它所属的范围。这个本应该是私有的数据,事实上已经变成公有的了。

Public class  UnsafeStates{

      Private String[] states = new String[]{“AK”,”AL”,...;

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

}

不正确的发布对象 -This 引用在构造时逸出,当对象并没有完全构造好就被新线程使用。

Public class ThisEscape{

Public ThisEscape(){

      New Thread(){

                 Public void   run(){

                      doSomething();

doSomething1();

                 }

           }).start();

}

 

注意对象只有通过构造函数返回后,才处于可预言的、稳定的状态,所以从构造函数内部发布的对象只是一个未完成构造的对象。甚至即使是在构造函数的最后一行发布的引用也是如此。

 

3. 线程封闭

3.1   栈限制

栈限制是线程限制的一种特例,在栈限制中,只能通过本地变量才可以触及对象,本地变量使对象更容易被限制在线程本地中。本地变量本身就被限制在执行线程中;它们存在于执行线程栈。

3.2   ThreadLocal

ThreadLocal 把变量限制在线程内访问,这样两个线程之间不存在共享访问的问题,两个线程各自维护自己的变量。下面的例子说明了,一个原本可以被多线程法访问的变量,经过 ThreadLocal 的改进,变成了只有当前线程才能访问和修改的变量,这样做自然线程就安全了。

public class ThreadLocalImageServlet extends HttpServlet{

      public ThreadLocal<String> imageURL = new ThreadLocal<String>(){

           public String initialValue(){

                 return "";

           }

      };

      protected void doGet(HttpServletRequest req, HttpServletResponse resp)

                 throws ServletException, IOException {

           imageURL.set(req.getParameter("imageURL"));

           resp.getWriter().println(imageURL.get());

      }

}

3.3   不可变性

 

 

分享到:
评论

相关推荐

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

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

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

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

    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类 ...

    Java并发编程基础.pdf

    Java并发编程基础主要包括以下几个核心方面: 线程与线程状态:理解Java中线程的基本概念,包括线程的创建、启动、暂停、恢复和终止。熟悉线程的生命周期及其不同状态,如新建、就绪、运行、阻塞和死亡。 线程同步...

    JAVA 并发编程实战

    Java并发编程实战,本书从线程的基础知识,包括线程安全性,对象共享以及对象组合灯,到结构化并发编程,都提供了很详细的讲解。

    Java并发编程实践 PDF 高清版

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

    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并发编程实战》读书笔记-第5章-基础构建模块

    《java并发编程实战》读书笔记-第3章-对象的共享,脑图形式,使用xmind8制作 包括同步容器类、并发容器类、阻塞队列和生产者消费者模式、阻塞和中断方法、同步工具类。最后是构建高效且可伸缩的结果缓存

    java并发编程理论基础精讲

    通过深入学习,您将建立坚实的并发编程基础,能够更好地理解和应对多线程编程中的挑战。 并发编程概述: 引入并发编程的基本概念,解释为什么多线程编程在现代应用中至关重要。 线程和进程: 解释线程和进程的区别,...

    Java并发编程实战2019.zip

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

    JAVA并发编程实践_中文版(1-16章全)_1/4

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

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

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

    java并发编程:线程基础

    本资源致力于向您介绍 Java 并发编程中的线程基础,涵盖了多线程编程的核心概念、线程的创建和管理,以及线程间通信的基本方法。通过深入学习,您将建立扎实的多线程编程基础,能够更好地理解和应用多线程编程。 多...

    java 并发编程实践 001

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

    Java并发编程学些手册

    Java并发编程学些手册,包括并发编程基础、volatile关键字、synchronized关键字、final关键字、对象的共享、同步工具类、线程池、锁、多线程实战等部分的详细介绍和解读。 无论你是面试,还是进阶,这些文章的内容...

    Java并发编程part2

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

    java源码包---java 源码 大量 实例

     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是最基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...

    Java并发编程实践part1

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

Global site tag (gtag.js) - Google Analytics