Java并发编程实战学习笔记 第三章 对象的共享

要编写正确的并发程序,关键在于访问的共享的可变状态时需要正确管理

一、可见性

为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

在没有同步的情况下,编译器、处理器、运行时都可能对操作的执行顺序进行一些意想不到的调整。在缺乏足够同步的多线程中,想要对内存操作的执行顺序进行判断,几乎无法得到正确的结论。

1.失效数据

在缺乏同步的程序中可能产生错误的结果的一种情况:失效数据,失效值可能不会同时出现:一个线程可能获得某个变量的最新值,而获得另一个变量的失效值。

2.非原子的64位操作

JVM允许将64 位的读操作或写操作分解为两个32为的操作,当取一个非volatile类型的变量long变量时,如果对改变量的读操作和写操作还不同的线程中执行,那么狠可能会读取到某个值的高32位和另一个值的低32位,因此在多线程中使用共享可变的double和long等类型的变量是不安全的,除非用关键字volatile来声明他们、或者用锁保护起来。

3.加锁与可见性

内置锁可用于确保某个线程以一种可预测的方式来查看另一个线程的执行结果。

加锁的含义不仅仅局限于互斥行为,好包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行度操作或者写操作的线程都必须在已同一个锁上同步。

4.Vloatile变量

java语言提供了一种稍微弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。volatile变量不会被缓存在寄存器或者其他处理器不可见的地方,因此在读取volatile变量时总会返回新写入的值。是一种比关键字sychronized更轻量的同步机制。

当且仅当满足以下所有条件时,才应该使用volatile变量:

(1)对变量的写入操作不依赖于变量的当时值、或者能确保只有单个线程更新变量的值。

(2)该变量不会与其他变量一起纳入不变性条件中

(3)在访问变量时 不需要加锁

二、发布与逸出

“发布(publish)”一个对象的意思是,是对象能够在当前作用域之外的代码中使用,如:将一个指向改对象的引用保存到其他代码可以访问的地方,或者在某一个非私有的方法中返回该引用、或将引用传递到其他类的方法中。

不要在构造过程中使用this引用逸出,一种常见的错误是,在构造函数中国启动另一个线程,当在构造函数中启动另一个线程时,无论是显式的还是隐式的创建,this引用都会被新的线程共享。在构造函数中调用一个可改写的实列方法时,同样会导致this引用在构造过程中逸出。

三、线程封闭

当访问共享的可变数据时,通常需要使用同步,一种避免使用同步的方式就是不共享数据。如果仅在单线程类访问数据,就不需要同步。这种技术被称之为线程封闭。

1.Ad-hoc线程封闭是指,维护线程封闭性的职责完全有程序实现来承担。由于Ad-hoc线程封闭技术非常脆弱,因此在程序中尽量少用,在可能的情况下,应该使用更强的线程封闭技术(如:站封闭、ThreadLocal类)

2.栈封闭

栈封闭式线程封闭的一种特例,在栈封闭中,只能通过局部的变量才能访问对象。

3.ThreadLocal类

维持线程封闭性的一种更规范的方法是使用ThreadLocal,这个类能使线程中的某个值与保存值的对象关联起来。通常用于防止对可变的单实例变或全局变量进行共享。、

4.不可变性

如果某个对象在被创建之后器状态就不能被改变,那么这个对象就称之为不可变对象,线程安全性是不可变对象的股友属性之一,不可变对象一定是线程安全的。

四、安全发布

任何线程都可以在不需要额外同步的情况下安全的访问不可变的对象,即使在发布这些对象是没有使用同步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值