19 Java内存模型与线程()

  本篇文章为你整理了19 Java内存模型与线程()的详细内容,包含有 19 Java内存模型与线程,希望能帮助你了解 19 Java内存模型与线程。

  目录1 锁优化历史2 自旋锁与自适应自旋2.1 关于自旋锁2.1 自旋锁优化:自适应自旋3 锁消除4 锁粗化5 轻量级锁6 偏向锁7 锁的优缺点对比

  1 锁优化历史

  synchronized 从 JDK1.0到JDK1.5 ,效率低

  JDK1.5到JDK1.6,JVM团队对synchronized进行深度优化,加入了:适应性自旋、锁消除、锁膨胀、轻量级锁、偏向锁 等优化技术

  JDK1.5 开始,加入java.util.concurrent,提供API层面的轻量级锁应用

  为什么优化synchronized?

  互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给Java虚拟机的并发性能带来了很大的压力。

  2 自旋锁与自适应自旋

  2.1 关于自旋锁

  自旋锁历史进程:首次出现在JDK1.4.2,但默认关闭(使用-XX:+UseSpinning参数开启),在JDK6开始默认开启。

  自旋锁实现逻辑:如果锁被其它线程占有,那么本线程不放弃处理器的执行时间,并执行一个忙循环(自旋),直至得到锁。

  自旋锁弊端:如果锁被占用的时间很长,那么自旋的线程只会白白消耗处理器资源,带来性能的浪费

  自旋锁优化:

  引入自旋次数:如果自旋超过了限定的次数仍然没有成功获得锁,就应当使用传统的方式去挂起线程。自旋次数的默认值是10次,可以启用参数-XX:PreBlockSpin来更改。(次数在JDK1.4.2已经实现)

  引入了自适应自旋

  2.1 自旋锁优化:自适应自旋

  原来:所有线程的自旋时间统一的(PreBlockSpin配置值 * 单次自旋时间)
 

  自适应自旋:自旋的时间不固定,JVM根据前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。
 

  自适应自旋情形:

  

例如1:线程A、B,锁L。A先通过自旋获取锁,那么JVM认为B也能通过自旋获取到锁,随即给B分配自旋时间,并且这个时间也是综合之前的自旋时间

 

  

 

  

例如2:锁L,线程A B C 通过自旋,都没有获取到锁,那么JVM会对后续的线程省略自旋过程,以免浪费处理器资源

 

  

 

  3 锁消除

  定义:指虚拟机即时编译器在运行时,对一些代码要求同步,但是对被检测到不可能存在共享数据竞争的锁进行消除。

  判断依据:源于逃逸分析的数据支持,如果判断到一段代码中,在堆上的所有数据都不会逃逸出去被其他线程访问到,那就可以把它们当作栈上数据对待,认为它们是线程私有的,同步加锁自然就无须再进行。

  举例:

  一段看起来没有同步的代码:

  

public String concatString(String s1, String s2, String s3) 

 

   return s1 + s2 + s3;

  

 

  javac编译后,会变为以下同等代码:

  

public String concatString(String s1, String s2, String s3) { 

 

   StringBuffer sb = new StringBuffer();

   sb.append(s1);

   sb.append(s2);

   sb.append(s3);

   return sb.toString();

  //append()方法有synchronize修饰

  

 

  分析:
 

  jvm观察变量sb,经过逃逸分析后会发现它的动态作用域被限制在concatString()方法内部。可以采用无锁操作。
 

  在解释执行时这里仍然会加锁,但在即时编译之后,这段代码就会忽略所有的同步措施而直接执行。

  锁消除总结:

  JVM会进行逃逸分析,符合条件的,在编译为机器码时,会消除所有同步措施

  4 锁粗化

  定义:假如一串零碎的操作都对同一个对象加锁,JVM会把加锁同步的范围扩展(粗化)到整个操作序列的外部

  举例:
 

  例如上面concatString()方法,将锁扩展到第一个append()操作之前最后一个append()操作之后,这样只需加锁一次

  5 轻量级锁

  逻辑:无竞争的情况下使用CAS操作去消除同步使用的互斥量
 

  轻量级锁提升性能的依据:“对于绝大部分的锁,在整个同步周期内都是不存在竞争的”这一经验法则
 

  过程分析:
 

  6 偏向锁

  逻辑:在无竞争的情况下把整个同步都消除掉,连CAS操作都不去做
 

  “偏”的理解:锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁一直没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。

  过程分析:后续补充

  7 锁的优缺点对比

  
加锁和解锁不需要CAS操作,没有额外的性能消耗,和执行非同步方法相比仅存在纳秒级的差距

  如果线程间存在锁竞争,会带来额外的锁撤销的消耗

  适用于只有一个线程访问同步块的场景

  
竞争的线程不会阻塞,提高了响应速度

  如线程成始终得不到锁竞争的线程,使用自旋会消耗CPU性能

  追求响应时间,同步块执行速度非常快

  
线程竞争不适用自旋,不会消耗CPU

  线程阻塞,响应时间缓慢,在多线程下,频繁的获取释放锁,会带来巨大的性能消耗

  追求吞吐量,同步块执行速度较长

  以上就是19 Java内存模型与线程()的详细内容,想要了解更多 19 Java内存模型与线程的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: