浅谈java内置锁synchronized

1、synchronized使用

synchronized是java提供的关键字,用来实现同步,主要用法有以下几种:

  • 同步代码块,锁是括号里面的对象
synchronized(object) {
    //在此代码中访问共享数据
}
  • 同步方法,锁是当前实例对象
public synchronsized int isEmpty() {
  //在此代码中访问共享数据
}
  • 静态同步方法,锁是当前类的Class对象

一个线程试图访问同步代码时,首先必须得到锁,退出和抛异常时,必须释放锁,保证了同一时间只能有一个线程访问共享资源,从而保证了线程安全。

2、synchronized实现原理
  • synchronzied基于jvm实现,具体来讲,是基于进入和退出Monitor对象实现同步,代码块同步是使用monitorenter、monitorexit指令实现,而方法同步是使用另一种方法实现的;
  • monitorenter、和monitorexit在代码编译后被分别插入同步代码的开始位置和结束位置(异常位置也有),当执行到monitorenter时,将会尝试获取minitor的所有权,及对象的锁。
  • 每一个对象都有一个monitor与之关联,当monitor被持有时,对象即被锁定;
下面通过示例代码看下同步代码快的实现:
//以下代码并无实际意义,只为说明问题
public class synchronizedTest {
    public int getState(){
        Object o = new Object();
        synchronized (o) {
            for(int i=0;i<1000;i++) {
                System.out.println(i);
            }
        }
        return 1;
    }
}

使用javap反编译之后可以看到monitorenter、monitorexit两个指令(11行、35行、42行)

public class synchronizedTest {
  public synchronizedTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public int getState();
    Code:
      /...../
       9: dup
      10: astore_2
      11: monitorenter
      12: iconst_0
      13: istore_3
      /...../
      31: goto          14
      34: aload_2
      35: monitorexit
      36: goto          46
      39: astore        4
      41: aload_2
      42: monitorexit
      43: aload         4
      45: athrow
      /....../
}

事实上,只有在JDK1.6之前,synchronized的实现才会直接调用ObjectMonitor的enter和exit,这种锁被称之为重量级锁。为什么说这种方式操作锁很重呢?

  • Java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就要从用户态转换到核心态,而这种上下文处理会花费很多的处理器时间,对于代码简单的同步块(如被synchronized修饰的get 或set方法)状态转换消耗的时间有可能比用户代码执行的时间还要长,所以说synchronized是java语言中一个重量级锁。
  • JDK1.6之后 对锁做了很多优化,包括:偏向锁、轻量级锁等,后面会继续更新。

参考:
1、https://www.hollischuang.com/archives/2030
2、《并发编程的艺术》

欢迎扫码关注公众号共同升级打怪吖

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容