浅谈Java锁

栏目: Java · 发布时间: 5年前

内容简介:在一秒钟内看到本质的人和花半辈子也看不清一件事本质的人,自然是不一样的命运。——马里奥·普佐每当遇到Java面试,“锁”是个必然会被提到的东西。那么,在面试中,谈“锁”都会谈论些什么呢,诸位看官又是否对“锁”有足够的了解?

在一秒钟内看到本质的人和花半辈子也看不清一件事本质的人,自然是不一样的命运。

——马里奥·普佐

每当遇到 Java 面试,“锁”是个必然会被提到的东西。那么,在面试中,谈“锁”都会谈论些什么呢,诸位看官又是否对“锁”有足够的了解?

本文旨在剖析锁的底层原理,以及锁的应用场景。

一、Synchronized

1、一道面试题

同一个对象在A、B两个线程中分别访问该对象的两个同步方法writer和reader,是否会产生互斥?

class LockDemo{
	
	int a = 0;
	
	public synchronized void writer(){
		sleep(10);
		a++;
	}
	
	public synchronized void reader(){
		int i = a;
	}
	
	public static void main(String[] args){
	
        Test test = new Test();
        new Thread(() -> {
            test.writer();
        }).start();
        
        sleep(1);
        
        new Thread(() -> {
            test.reader();
        }).start();

    }

}

答案:会。因为synchronized修饰的是方法,锁是 对象锁 ,默认当前的对象作为锁的对象。只有当A释放锁之后,B才会获得对象的锁。

(1)如果是换成是不同对象呢?

不会互斥,因为锁的是 对象 ,而不是 方法

(2)如果writer、reader方法加上static修饰,两个线程中,类直接调用两个方法呢?

会互斥,因为锁的是Class对象。

(3)如果writer方法用static修饰,reader方法不用呢?

不会互斥。因为一个是对象锁,一个是Class对象锁,锁的类型不同。

synchronized修饰位置与锁的关系:

  • 同步方法 —— 对象锁,当前实例对象
  • 静态同步方法 —— 类对象锁,当前对象的Class对象
  • 同步方法块 —— 对象锁,synchonized括号里配置的对象

二、锁的底层实现

思考几个问题

  1. 对象锁、Class对象锁时如何实现的
  2. 为什么要这么设计,只设计一个对象锁或Class对象锁,有什么不好?

1、反编译

class LockDemo{
	
	static int a = 0;

    public synchronized void writer(){
        System.out.println("writer方法开始调用");
        a++;
        waitNs(20);
        System.out.println("writer方法调用结束");
    }

    public static synchronized void reader(){
        System.out.println("reader方法开始调用");
        int i = a;
        System.out.println("reader方法调用结束");
    }

    public void writer2(){

        synchronized (this) {
            a--;
        }
    }

}

使用 javacjavap -verbose 命令, 反编译 上述代码

...

{
  static int a;
    descriptor: I
    flags: ACC_STATIC

  public com.fonxian.entity.LockDemo();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 6: 0
  
  //同步方法
  public synchronized void writer();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String writer方法开始调用
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #5                  // Field a:I
        11: iconst_1
        12: iadd
        13: putstatic     #5                  // Field a:I
        16: bipush        20
        18: invokestatic  #6                  // Method waitNs:(I)V
        21: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        24: ldc           #7                  // String writer方法调用结束
        26: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        29: return
      LineNumberTable:
        line 11: 0
        line 12: 8
        line 13: 16
        line 14: 21
        line 15: 29

  //静态同步方法
  public static synchronized void reader();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=0
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #8                  // String reader方法开始调用
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #5                  // Field a:I
        11: istore_0
        12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        15: ldc           #9                  // String reader方法调用结束
        17: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        20: return
      LineNumberTable:
        line 18: 0
        line 19: 8
        line 20: 12
        line 21: 20
	
  //同步代码块
  public void writer2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: getstatic     #5                  // Field a:I
         7: iconst_1
         8: isub
         9: putstatic     #5                  // Field a:I
        12: aload_1
        13: monitorexit
        14: goto          22
        17: astore_2
        18: aload_1
        19: monitorexit
        20: aload_2
        21: athrow
        22: return
      Exception table:
         from    to  target type
             4    14    17   any
            17    20    17   any
      LineNumberTable:
        line 25: 0
        line 26: 4
        line 27: 12
        line 28: 22
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 17
          locals = [ class com/fonxian/entity/LockDemo, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
        frame_type = 250 /* chop */
          offset_delta = 4

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: iconst_0
         1: putstatic     #5                  // Field a:I
         4: return
      LineNumberTable:
        line 8: 0
}
SourceFile: "LockDemo.java"

同步代码块:使用monitorenter和monitorexit指令实现,通过监听器对象去 获得锁释放锁

同步方法、静态同步方法:使用修饰符 ACC_SYNCHRONIZED 实现。

二、锁的形式

JDK1.6之前,synchronized只有传统锁机制。

JDK1.6引入两种新的锁类型:偏向锁和轻量级锁。引入的目的是解决,没有多线程竞争或基本没有竞争的情况下,使用传统锁带来的性能问题。

锁的四种状态:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。锁可以升级,不能降级。

1、对象头

要了解锁的机制,首先要了解对象头。

Java对象头中的Mark Word默认存储对象的HashCode、分代年龄和锁标记位。

Java对象头的存储结构如下:

锁状态 25bit 4bit 1bit是否是偏向锁 2bit锁标志位
无锁状态 对象的hashCode 对象的分代年龄 0 01

Mark Word的状态变化:

锁状态 30bit 2bit
轻量级锁 指向栈中锁记录的指针 锁标志位00
重量级锁 指向互斥量的指针 锁标志位10
锁状态 23bit 3bit 3bit 1bit 2bit
偏向锁 线程ID Epoch 对象分代年龄 1 01

以上所述就是小编给大家介绍的《浅谈Java锁》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Concepts, Techniques, and Models of Computer Programming

Concepts, Techniques, and Models of Computer Programming

Peter Van Roy、Seif Haridi / The MIT Press / 2004-2-20 / USD 78.00

This innovative text presents computer programming as a unified discipline in a way that is both practical and scientifically sound. The book focuses on techniques of lasting value and explains them p......一起来看看 《Concepts, Techniques, and Models of Computer Programming》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具