美文网首页
java虚拟机-线程安全与锁优化

java虚拟机-线程安全与锁优化

作者: 白六小子 | 来源:发表于2018-08-13 22:14 被阅读9次

    当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方法进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。——Brain Goetz


    一、java中的线程安全

    多个线程之间存在共享数据竞争是线程安全解决问题的前提。
    如果将线程安全归为非真即假的二元选项,按照线程安全的程度由强至弱,可以分为以下五类

    • 不可变
      被final修饰的数据类型一但被正确构建出来之后就是不可变的。
      String, Long, Double等
    • 绝对线程安全
      javaAPI提供的标榜自己是线程安全的类大多情况下不上绝对线程安全的。如Vector的使用,有时需要手动添加同步措施。
    • 相对线程安全
      调用端需要采取一些额外的同步措施,如Vector, HashTable,Collections的synchronizedCollection()方法包装的集合等。

    二、常见的线程安全实现的方法

    1. 互斥同步

    何为同步?
    多个线程并发访问共享数据时,保证共享数据在同一时刻只被一个线程使用。
    何为互斥?
    互斥是实现同步的手段,临界区,互斥量,信号量都是主要的互斥实现方式。因此互斥是因,同步是果。互斥是方法,同步是目的。
    如何实现同步互斥?
    (1)synchronized
    该关键字经过编译后会在同步块的前后分别形成moniterenter和monitorexit这两个字节码指令。

    这两个字节码指令都需要一个reference类型的参数来指定要锁和解锁的对象。如果java程序中明确指明了这个对象参数,那就是这个对象的reference。如果没有明确指定,那就根据synchronized修饰的是实例方法还是类方法,去取对应的对象实例货class对象作为锁对象。
    执行monitorenter时锁计数器加1,执行monitorexit时锁计数减1,锁计数器为0时就释放锁,如果获取锁失败就阻塞等待,知道对象锁被另外一个线程释放。

    (2)ReentrantLock
    lock和unlock配合try/finally使用

    synchronized和reentrantlock两者都是可重入锁。
    何为可重入锁?:一个线程或得了某对象锁后,后续执行该对象上的其他加锁方法不会阻塞而会直接获取锁,即一个线程获取锁的时候不会自己把自己锁死。 
    

    (3)reentrantlock与synchronized的区别

    • reentrantlock等待可中断
    • reentrantlock可以实现公平锁
    • reentrantlock可以绑定多个condition

    两者性能并无多少差别,使用时以合适的场景和方便为主。

    2. 无同步方案

    (1)ThreadLocal
    线程本地私有变量。是以map的形式存储变量Key—Value。其中key为当前变量,value为要存储的值。用数组来存储,本质上是拉链法来解决hash冲突。

    相关文章

      网友评论

          本文标题:java虚拟机-线程安全与锁优化

          本文链接:https://www.haomeiwen.com/subject/oxypbftx.html