2.3线程安全相关概念

学习使用哪种同步机制来实现线程安全

对象的发布与逸出


发布(publish) 使对象能够在当前作用域之外的代码中使用

逸出(escape) 当某个不应该发布的对象被发布了


常见逸出的有下面几种方式:

  • 静态域逸出
  • public修饰的get方法
  • 方法参数传递
  • 隐式的this
安全发布对象
  • 在静态域中直接初始化public static Person = new Person();

    • 静态初始化由JVM在类的初始化阶段就执行了,JVM内部存在着同步机制,致使这种方式我们可以安全发布对象
  • 对应的引用保存到volatile或者AtomicReferance引用中

    • 保证了该对象的引用的可见性和原子性
  • 由final修饰

    • 该对象是不可变的,那么线程就一定是安全的,所以是安全发布
  • 由锁来保护

    • 发布和使用的时候都需要加锁,这样才保证能够该对象不会逸出

解决多线程遇到的问题

java实现线程安全:
  • 无状态(没有共享变量)

  • 使用final使该引用变量不可变(如果该对象引用也引用了其他的对象,那么无论是发布或者使用时都需要加锁)

  • 加锁(内置锁,显示Lock锁)

  • 使用JDK为我们提供的类来实现线程安全(此部分的类就很多了)

    • 原子性(就比如上面的count++操作,可以使用AtomicLong来实现原子性,那么在增加的时候就不会出差错了!)
    • 容器(ConcurrentHashMap等等…)
    • ……
  • …等等

原子性和可见性

JDK中有atomic包提供给我们实现原子性操作(AtomicLong,LongAdder,AtomicLongArray,AtomicLongFieldUpdater[属性原子修改器]等)

对于可见性,java提供了一个关键字volatile(轻量级同步机制)

volatile经典总结:volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性

  • 保证该变量对所有线程的可见性

    • 在多线程的环境下:当这个变量修改时,所有的线程都会知道该变量被修改了,也就是所谓的“可见性”
  • 不保证原子性

    • 修改变量(赋值)实质上是在JVM中分了好几步,而在这几步内(从装载变量到修改),它是不安全的

使用了volatile修饰的变量保证了三点

  • 一旦你完成写入,任何访问这个字段的线程将会得到最新的值
  • 在你写入前,会保证所有之前发生的事已经发生,并且任何更新过的数据值也是可见的,因为内存屏障会把之前的写入值都刷新到缓存。
  • volatile可以防止重排序(重排序指的就是:程序执行的时候,CPU、编译器可能会对执行顺序做一些调整,导致执行的顺序并不是从上往下的。从而出现了一些意想不到的效果)。而如果声明了volatile,那么CPU、编译器就会知道这个变量是共享的,不会被缓存在寄存器或者其他不可见的地方。

一般来说,volatile大多用于标志位上(判断操作),满足下面的条件才应该使用volatile修饰变量:

  • 修改变量时不依赖变量的当前值(因为volatile是不保证原子性的)
  • 该变量不会纳入到不变性条件中(该变量是可变的)
  • 在访问变量的时候不需要加锁(加锁就没必要使用volatile这种轻量级同步机制了)
线程封闭[不使用成员变量(不共享数据)]

Servlet所有的数据都是在方法(栈封闭)上操作的,每个线程都拥有自己的变量,互不干扰

线程封闭上还有另一种方法,就是ThreadLocal,这个类的API就可以保证每个线程自己独占一个变量

不变性

String就是一个不可变对象,没有遵循“对象所有的域都是final修饰的”,因为JVM在内部做了优化的。

final

final仅仅是不能修改该变量的引用,但是引用里边的数据是可以改的

final HashMap hashMap = new HashMap<>();

不可变的对象引用在使用的时候还是需要加锁

  • 或者把Person也设计成是一个线程安全的类
  • 因为内部的状态是可变的,不加锁或者Person不是线程安全类,操作都是有危险的

设计成不可变对象的要点:

  • 对象创建后状态就不能修改
  • 对象所有的域都是final修饰的
  • 对象是正确创建的(没有this引用逸出)
线程安全性委托

很多时候我们要实现线程安全未必就需要自己加锁,自己来设计

我们可以使用JDK给我们提供的对象来完成线程安全的设计。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值