博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发编程面试题——synchronized的底层实现
阅读量:2427 次
发布时间:2019-05-10

本文共 1209 字,大约阅读时间需要 4 分钟。

synchronized实现原理

synchronized代码块:

首先我们先建立一个synchronized同步语句块:

public class SynchronizedTest {	public void method() {		synchronized(this) {			System.out.println("synchronized");

然后对其进行反编译:

在这里插入图片描述

monitorenter

每个对象有一个监视器锁(monitor),当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

  • 如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者
  • 如果线程已经占有该monitor,则重新进入
  • 如果其他线程已经占用了该monitor,则该线程进入阻塞状态,直至monitor的进入数为0,再尝试重新获取monitor的所有权
monitorexit

执行monitorexit的线程必须是共享变量所对应的monitor的所有者,指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者,其他被阻塞的线程可以尝试去获取这个monitor的所有权

在这里插入图片描述
我们可以看到,在执行synchronized同步代码块时,在最后会有两个monitorexit,这个主要是防止在同步代码块中线程因异常退出,而锁没有得到释放,这必然会造成死锁(等待的线程永远获取不到锁)。因此最后一个monitorexit是保证在异常情况下,锁也可以得到释放,避免死锁

synchronized方法:

public class SynchronizedMethod {    public synchronized void method2(){        System.out.println("Synchronized2");    }}

在这里插入图片描述

对于synchronized方法而言,javac为其生成了一个ACC_SYNCHRONIZED关键字,在JVM进行方法调用时,发现调用的方法被ACC_SYNCHRONIZED修饰,则会先尝试获得锁

什么是自旋

很多synchronized里面的代码只是一些很简单的代码,执行时间非常快,此时等待的线程都加锁可能不是一种合适的操作,因为线程阻塞设计到用户态和内核态切换的问题,既然synchronized里面的代码执行得非常快,那么可以让等待锁的线程不要被阻塞,而是在synchronized的边界做忙循环,这就是自选

轻量级锁

锁的状态总共有四种:无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级到重量级锁(锁的升级是单项的,也就是说只能从低到高升级,不会出现锁的降级)

转载地址:http://nhjmb.baihongyu.com/

你可能感兴趣的文章
Shell 中 getopts 示例用法
查看>>
Shell netcat / nc 命令
查看>>
shell—字符串截取和去重
查看>>
修改无盘网络启动镜像
查看>>
SSHD的key_read报错的解决方法
查看>>
win10更新后输入密码后无限循环解决方法
查看>>
离线安装wxpython
查看>>
升级glibc导致ssh登录出现问题
查看>>
Shell中管道命令返回值
查看>>
python配置解析模块ConfigParser
查看>>
python获取对象信息模块inspect
查看>>
python命令行解析模块argparse
查看>>
bottle学习之使用socket获取本机IP和主机名
查看>>
bottle学习之JSON模块
查看>>
python 查询模块内函数
查看>>
python模块—— os
查看>>
利用lvs+keepalived实现负载均衡
查看>>
离线环境下安装flask
查看>>
Python-Flask学习:ImportError: No module named ext.script
查看>>
Flask-Bootstrap使用本地CSS和JS
查看>>