Java 隐式锁 - synchronized 关键字

2019-09-15  

Java 中关键字 synchronized 表示只有一个线程可以获取作用对象的锁,执行代码,阻塞其他线程。

作用:

  • 确保线程互斥地访问同步代码
  • 保证共享变量的修改能够及时可见
  • 有效解决重排序问题

 

用法:

  • 修饰普通方法
  • 修饰静态方法
  • 指定对象,修饰代码块

 

特点:

  • 阻塞未获取到锁、竞争同一个对象锁的线程
  • 获取锁无法设置超时
  • 无法实现公平锁
  • 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll()
  • 锁的功能是 JVM 层面实现的
  • 在加锁代码块执行完或者出现异常,自动释放锁

 

原理:

  • 同步代码块是通过 monitorenter 和 monitorexit 指令获取线程的执行权
  • 同步方法通过加 ACC_SYNCHRONIZED 标识实现线程的执行权的控制

 

测试代码:

public class TestSynchronized {
	
	public void sync() {
		synchronized (this) {
			System.out.println("sync");
		}
	}
	
	public synchronized void syncdo() {
		System.out.println("syncdo");
	}
	
	public static synchronized void staticSyncdo() {
		System.out.println("staticSyncdo");
	}
}

 

通过JDK 反汇编指令 javap -c -v TestSynchronized

javap -c -v TestSynchronized
 
  Last modified 2019-5-27; size 719 bytes
  MD5 checksum e5058a43e76fe1cff6748d4eb1565658
  Compiled from "TestSynchronized.java"
public class constxiong.interview.TestSynchronized
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // constxiong/interview/TestSynchronized
   #2 = Utf8               constxiong/interview/TestSynchronized
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lconstxiong/interview/TestSynchronized;
  #14 = Utf8               sync
  #15 = Fieldref           #16.#18        // java/lang/System.out:Ljava/io/PrintStream;
  #16 = Class              #17            // java/lang/System
  #17 = Utf8               java/lang/System
  #18 = NameAndType        #19:#20        // out:Ljava/io/PrintStream;
  #19 = Utf8               out
  #20 = Utf8               Ljava/io/PrintStream;
  #21 = String             #14            // sync
  #22 = Methodref          #23.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #23 = Class              #24            // java/io/PrintStream
  #24 = Utf8               java/io/PrintStream
  #25 = NameAndType        #26:#27        // println:(Ljava/lang/String;)V
  #26 = Utf8               println
  #27 = Utf8               (Ljava/lang/String;)V
  #28 = Utf8               syncdo
  #29 = String             #28            // syncdo
  #30 = Utf8               staticSyncdo
  #31 = String             #30            // staticSyncdo
  #32 = Utf8               SourceFile
  #33 = Utf8               TestSynchronized.java
{
  public constxiong.interview.TestSynchronized();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lconstxiong/interview/TestSynchronized;
 
  public void sync();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #21                 // String sync
         9: invokevirtual #22                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: aload_1
        13: monitorexit
        14: goto          20
        17: aload_1
        18: monitorexit
        19: athrow
        20: return
      Exception table:
         from    to  target type
             4    14    17   any
            17    19    17   any
      LineNumberTable:
        line 6: 0
        line 7: 4
        line 6: 12
        line 9: 20
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      21     0  this   Lconstxiong/interview/TestSynchronized;
 
  public synchronized void syncdo();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #29                 // String syncdo
         5: invokevirtual #22                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 12: 0
        line 13: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lconstxiong/interview/TestSynchronized;
 
  public static synchronized void staticSyncdo();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #31                 // String staticSyncdo
         5: invokevirtual #22                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 16: 0
        line 17: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
}
SourceFile: "TestSynchronized.java"

 

 

ConstXiong 备案号:苏ICP备16009629号-3