深入理解java虚拟机--线程安全与锁优化

面向过程编程思想和面向对象编程思想

面向过程编程思想:站在计算机的角度,以算法为核心,数据是客体,程序代码处理数据。
面向对象编程思想:站在现实世界的角度,数据和行为视为对象的一部分。

java语言中的线程安全

5类共享数据类别:1.不可变;2.绝对线程安全;3.相对线程安全;4.线程兼容;5.线程对立。

  1. 不可变(final)
    不可变带来的安全性是最简单和最纯粹的。基本数据类型,final关键字修饰;共享数据是一个对象,对象的行为用final修饰。
  2. 绝对线程安全
    定义:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。
  3. 相对线程安全
    单独操作是线程安全的;需要额外的同步手段(特定顺序的连续调用)。
    例子:Vector的get()、remove()、size()等方法;其他类如:HashTable等。
  4. 线程兼容
    本身不是线程安全的;需要正确使用同步手段。
    例子:Vector的get()、remove()、size()等方法;其他类如:ArrayList、HashMap等。
  5. 线程对立
    无论是采取何种同步措施,都无法达到线程安全的。
    例子:Thread类的suspend()和resume();其他类如:System类的setInt()、setOut()和runFinalizersOnExit()等。

线程安全的实现方法

3种实现方法:1.互斥同步;2.非阻塞同步;3.无同步方案。

  1. 互斥同步
    也称阻塞同步;互斥是方法,同步是目的;互斥的实现方式主要有三种:临界区,互斥量,信号量。实现同步手段:synchronized和ReentrantLock。
  • synchronized:原生语法层面的互斥;关键字经过编译后在同步块前后形成monitorenter和monitorexit两个字节码指令,这两字字节码指令都需要一个reference类型的参数来指明要锁定和解锁的对象;如果synchronized修饰的实例方法则去取对应的对象实例,如果修饰的是类方法,则去取Class对象所为锁对象。有两点要注意的:1.synchronized同步块对同一条线程来说是可重入的,不会出现自己把自己锁死的情况;2.同步块在已进入的线程执行完之前,会阻塞后面其他线程的进入。

  • ReentrantLock:API层面的互斥;相对于synchronized来说有三个高级特性:1.等待可中断;2.可实现公平锁;3.锁可以绑定多个条件;

  • synchronized和ReentrantLock吞吐量比较
    jdk1.5版本:ReentrantLock>synchronized;
    jdk1.6后版本:synchronized、ReentrantLock两者持平;

  • 处理问题方式角度:互斥同步是悲观策略。

    阻塞和唤醒一个线程,需要从用户态转换到核心态,消耗性能。

  1. 非阻塞同步
  • 定义

    基于冲突检测的乐观并发策略,先进行操作,如果没有其他线程的竞争共享数据,那操作就是成功了;如果共享数据有争用,产生了冲突,那就再采取其他的补充措施(最常见的补偿措施就是不断的重试,直到成功为止),这种乐观的策略很多实现都不需要把线程挂起。

  • 处理问题方式角度:非阻塞同步是乐观策略。

  • CAS指令
    内存位置(V)、旧的预期值(A)、新值(B);
    CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不执行更新,但是无论是否更新了V的值,都会返回V的旧值,上述的处理过程是一个原子操作。

    CAS漏铜,ABA问题:
    如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说它的值没有被其他线程改变过了吗?如果在这段期间它的值曾经被改成了B,后来又被改成了A,那CAS操作就会误认为它从来没有被改变过。

  1. 无同步方案

    2类:1.可重入代码;2.线程本地存储。

    1. 可重入代码
      3个特征:不依赖存储在堆上的数据和公用的系统资源、用到的状态量都是由参数传入、不调用非可重入的方法。

    2. 线程本地存储
      例子:生产者-消费者:Web交互模型中的"一个请求对应一个服务器线程"的处理方式。

锁优化

5种锁优化:1.自旋锁和自适应自旋;2.锁消除;3.锁粗化;4.轻量级锁;5.偏向锁。

  1. 自旋锁和自适应自旋
  • 自旋锁定义
    是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁。
  • 自适应自旋定义
    • 自旋的时间不在固定,由前一次在同一个锁上的自旋时间及锁的拥有者的状态决定。
  • 原因
    • 挂起线程和唤醒线程会消耗处理器时间
    • 共享数据的锁定状态很多情况只会持续很短的时间
  1. 锁消除
  • 定义
    指在虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。
  1. 锁粗化
    范围扩大,如果虚拟机探测到有这样的一串零碎的操作都是对同一个对象加锁,将会把加锁同步的范围扩展(粗化)到整个操作序列的外部,这样只需要加锁一次就可以了。

  2. 轻量级锁

  • 没有多线程的竞争前提下;减少传统的重量级所使用操作系统互斥量产生的性能消耗。
  • Mark Word
  1. 偏向锁
  • 消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。
  • 不用做CAS操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值