第3章 对象的共享
来源:互联网 发布:练钢琴软件 编辑:程序博客网 时间:2024/05/17 09:40
第3章 对象的共享
3.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; }}
在没有同步的情况下,编译器、处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整。在缺乏足够同步的多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得出正确的结论。
3.1.1 失效数据
3.1.2 非原子的64位操作
最低安全性适用于绝大多数变量,但是存在一个例外:非volatile类型的64位数值变量(double和long)。
64位的读操作和写操作分解为两个32位的操作。当读取一个非volatile类型的long变量时,如果对该变量的读操作和写操作在不同的线程中执行,那么很可能会读取到某个值的高32位和另一个值的低32位。
用关键字volatile来声明它们,或者用锁保护,来确保安全。
3.1.3 加锁和可见性
加锁的含义不仅仅局限于互斥行为,还包括内存可见性。位了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。
3.1.4 Volatile 变量
Java语言提供了 一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。然而,在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一个种比sychronized关键字更轻量级的同步机制。
仅当volatile变量能简化代码的实现以及对同步策略的验证时,才应该使用它们。如果在验证正确性时需要对可见性进行复杂的判断,那么就不要使用volatile变量。volatile变量的正确使用方式包括:确保它们自身状态的可见性,确保它们所引用对象的状态的可见性,以及标识一些重要的程序生命周期事件的发生。
加锁机制即可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
当且仅当满足以下所有条件时,才应该使用volatile变量:
*对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
*该变量不会与其他状态变量一起纳入不变性条件中。
*在访问变量时不需要加锁。
3.2发布与逸出
安全的对象构造过程
不要在构造过程中使this引用逸出。
3.3线程封闭
一种避免使用同步的方式就是不共享数据。这种技术被称为线程封闭,它是实现线程安全性的最简单方式之一。当某个对象封闭在一个线程中时,这种用法将自动实现线程安全性,即使被封闭的对象本身不是线程安全的。
3.3.1Ad-hoc线程封闭
很少用
3.3.2栈封闭
栈封闭是线程封闭的一种特例,在栈封闭中,只能通过局部变量才能访问对象。局部变量的固有属性之一就是封闭在执行线程中。它们位于执行线程的栈中,其他线程无法访问这个栈。
3.3.3 ThreadLocal类
Java并发编程:深入解析ThreadLocal
ThreadLocal类能使线程中的某个值与保存值的对象关联起来。ThreadLocal提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回由当前执行线程在调用set时设置的最新值。
ThreadLocal对象通常用于防止对可变的单实例变量或全局变量进行共享。例如:通过将JDBC的连接保存到ThreadLocal对象中,每个线程都会拥有属于自己的连接。
当某个线程初次调用ThreadLocal.get方法时,就会调用initialValue来获取初始值。
3.4不变性
满足同步需求的另一种方法是使用 不可变对象。
不可变对象一定是线程安全的。
当满足一下条件时,对象才是不可变的:
*对象创建以后其状态就不能修改。
*对象的所有域都是final类型
3.4.1Final域
在Java内存模型中,final域还有着特殊的语义。final域能确保初始化过程的安全性,从而可以不受限制地访问不可变对象,并在共享这些对象时无须同步。
3.4.2示例:使用Volatile类型来发布不可变对象
3.5安全发布
3.5.1不正确的发布:正确的对象被破坏
3.5.2不可变对象与初始化安全性
3.5.3安全发布的常用模式
要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式来安全地发布:
*在静态初始化函数中初始化一个对象引用
*将对象的引用保存到volatile类型的域或者AtomicReference对象中。
*将对象的引用保存到某个正确构造对象的final类型域中。
*将对象的引用保存到一个由锁保护的域中。
3.5.4事实不可变对象
3.5.5可变对象
3.5.6安全地共享对象
- 第3章 对象的共享
- 第3章 对象的共享
- 第3章-对象的共享
- 第3章 对象的共享
- 第3章-对象的共享
- 3 对象的共享
- 3对象的共享
- 3对象的共享
- 第二章 对象的共享
- java并发编程 第三节 对象的共享
- 多线程系列提高(3)--对象的共享
- 第2章第1节练习题3 共享栈的基本操作
- 共享对象的实现
- 对象的共享
- 对象的共享
- 3. 对象的共享
- 对象的共享
- 对象的共享
- 解决:C语言调用pcap库出现unknown types error
- php 反射机制
- 看雪论坛大神的破解游戏反调试思路
- Paths - 2
- ReactJs + BootStrap + Pager 分页
- 第3章 对象的共享
- 实现类似网易邮箱的顶部工具栏的悬停效果
- python 装饰器模式 我的理解
- 搜狗技术团队为何从oracle转mysql 【转】
- 侧边栏 SlidingMenu
- 46. Permutations && 47. Permutations II
- 选择排序
- 30 天学习 30 种新技术
- c++编程四舍五入算法