第二章:Java并发机制的底层实现原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013068377/article/details/83021344

一、volatile的应用

volatile是轻量级的synchronized,在多线程中保证了共享变量的"可见性"。如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度

volatile的定义与实现原理

volatile修饰的共享变量,在多核处理器下会引发两件事情:

  • 将当前处理器缓存航的数据写会到系统内存
  • 这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效

为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到缓存后再进行操作,但操作完不知道何时会写到内存。如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存。同时其他处理器会将缓存中该变量的数据置为无效(缓存一致性协议),从内存中重新读取;

volatile的使用优化

举例:
队列集合:LinkedTransferQueue 使用追加字节的方式优化队列的出队和入队性能;

并不是所有的使用volatile的变量都应该追加到64个字节:
追加字节,与处理器的缓存行处理字节数相关,有些处理器的缓存行是32个字节宽,就没有必要增加字节;
如果共享变量不会被频繁的写,锁几率非常小,也没有必要通过追加字节的方式来避免相互锁定;

二、Synchronized的实现原理和应用

synchronized实现同步的基础,Java中的每一个对象都可以作为锁,具体表现为下面三种形式:

  • 对于普通同步方法,锁时当前实力对象
  • 对于静态同步方法,锁时当前类的Class对象
  • 对于同步方法块,锁时Synchronized括号里配置的对象

Java对象头

synchronized用的锁是存储在对象头中的;如果对象是数组类型,则虚拟机用3个字节宽存储对象头,如果对象是非数组类型,则用2个字节宽存储对象头;

锁的升级与对比

JavaSE1.6为了减少获得锁和释放锁带来的性能消耗,引入了"偏向锁"和"轻量级锁";在JavaSE1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁、轻量级锁、重量级锁,这几个状态会随着竞争情况逐渐升级;
锁可以升级,但不能降级,目的是为了提高获得锁和释放锁的效率;

锁的优缺点与对比

优点 缺点 适用场景
偏向锁 加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距 如果线程间存在锁竞争,会带来额外的锁撤销的消耗 适用于只有一个线程访问同步块场景
轻量级锁 竞争的线程不会阻塞,提高了程序的响应速度 如果始终得不到锁竞争的线程,使用自旋会消耗CPU 追求响应时间,同步块执行速度非常快
重量级锁 线程竞争不适用自旋,不会消耗CPU 线程阻塞,响应时间慢 追求吞吐量,同步块响应时间长

Java如何实现原子操作

  • 使用CAS实现原子操作
    JDK并发包里提供了一些使用CAS支持原子操作的类,如:AtomicBoolean,AtomicInteger,AtomicLong,同时提供了有用的工具方法,比如自增、自减;

  • 使用锁机制实现原子操作

猜你喜欢

转载自blog.csdn.net/u013068377/article/details/83021344