synchronized既保证原子性,又保证内存可见性,是一种线程同步的方式,是锁机制的一种java实现。synchronized的实现基于JVM底层,JVM是基于monitor实现的,而monitor的实现依赖于操做系统的互斥实现。
html
synchronized语义是同步,但同步有两层含义:java
互斥保证在线程退出前,全部对象状态变动都对其余线程不可见;可见保证在线程进入同步代码块时,能够看到上一个线程对对象状态变动的最终状态。编程
线程安全代表在多线程环境中,不会有多个线程同时访问共享数据。
线程同步是线程访问类和实例字段变量,和其余共享资源的一种串行化行为,确保在同一时间只能有一个线程访问资源。举个栗子,春运火车票只剩下最后一张火车票,A,B都要抢这张火车票,怎么解决这个问题防止超卖呢?把资源保护起来,让A,B排队来买火车票。
线程安全是属性,线程同步是方式。安全
synchronized同步代码块是经过monitorenter和monitorexit指令实现的,而synchronized同步方法是基于ACC_SYCHRONIZED标志,同步方法被调用时JVM会检查这个标志。monitorenter标记临界区的开始,线程执行到 monitorenter 指令时,将会尝试获取对象所对应的 monitor 的全部权;monitorexit标记临界区的结束,线程执行到 monitorexit 指令时,将释放对象所对应的 monitor 的全部权。多线程
1 public class SynchronizedMethod { 2 public synchronized void methodA() { 3 System.out.println("MethodA start"); 4 5 } 6 }
将这段代码经过 javap -c
反编译一下,重点关注一下编译后的第3行和第13行。并发
1 Compiled from "SynchronizedTest.java" 2 public class com.memory.SynchronizedTest { 3 public com.memory.SynchronizedTest(); 4 Code: 5 0: aload_0 6 1: invokespecial #1 // Method java/lang/Object."<init>":()V 7 4: return 8 9 public void methodA(); 10 Code: 11 0: aload_0 12 1: dup 13 2: astore_1 14 3: monitorenter 15 4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 16 7: ldc #3 // String MethodA start 17 9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 18 12: aload_1 19 13: monitorexit 20 14: goto 22 21 17: astore_2 22 18: aload_1 23 19: monitorexit 24 20: aload_2 25 21: athrow 26 22: return 27 Exception table: 28 from to target type 29 4 14 17 any 30 17 20 17 any 31 }
锁的种类oracle
java synchronized锁升级
JDK1.6中对synchronized优化引入了偏向锁,轻量级锁,重量级锁。锁的升级过程是单方向的,只容许从低到高升级,不容许降级。oop
重量级锁(Heavyweight Lock)是将程序运行交出控制权,将线程挂起,由操做系统来负责线程间的调度,负责线程的阻塞和执行。这样会出现频繁地对线程运行状态的切换,线程的挂起和唤醒,消耗大量的系统资源,致使性能低下。post
轻量级锁(lightweight Locking)是相对于重量级锁而言的,在synchronized实现中使用自旋的方式,实际是经过CPU自旋等待的方式替代线程切换,竞争的线程不会所以而阻塞,避免阻塞唤醒形成的CPU负荷。采用自旋的方式有利有弊,当锁占用的时间较短时,较少次数的自旋等待就能够获取锁;但在锁占用的时间较长时,自旋会白白浪费大量的CPU资源。所以自旋的次数有必定要在限定以内,自旋失败就会当即将锁升级为重量级锁,称为锁膨胀。性能
偏向锁(Biased Locking )从字面含义是这把锁是有私心的,会倾向于上次访问的线程。Hotspot的做者在他的论文《QRL-OpLocks-BiasedLocking》中阐述到,研究发现大多数状况下不存在多线程争夺共享资源,并且老是由同一线程屡次得到,考虑到CAS (Compare-And-Swap)指令在获取Java监视器时会形成较大的CPU延迟,为了让线程得到锁的代价更低而引入了偏向锁。
64位虚拟机中,标记字段(Mark Word)中包含哈希吗(HashCode,存放31bits对象的hashcode值),GC分代年龄(Generational GC Age,4bits,所以分代年龄最高为15),偏向线程ID,偏向锁标记。
synchronized锁的四个状态:无锁状态,偏向锁,轻量级锁和重量级锁,在Mark Word中对应不一样的字段。java synchronized不一样级别锁中的Mark Word
我是葛一凡,但愿对你有用。