继续面试大纲系列文章。

  从这一篇开始,我们进入ava编程中的一个重要领域---多线程!多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生;而滥用则会遭其反噬。

  在多线程编程中要渡的首个“劫”,则是Synchronized。了解其底层实现,无论是在面试中还是在平时工作中,都大有裨益。我们知其然,知其所以然,才能得心应手少挖坑。

  我们知道,多线程的核心思想是通过增加线程数量来并发的运行,来提高效率,也就是数量决胜论,而不是质量决胜(提高每个线程的处理能力)。多线程编程中面临的最大挑战,是如何解决多个线程同时修改一个公用的变量所带来的变量值不确定性问题。顺着这个思路分析,常用办法,无非就是,要么对变量动手,在一个线程修改时,变量值被锁定。要么是对修改的操作动手,在该段代码执行时,对其加锁,其他线程不可以在同一时刻进入该段代码执行。

  Synchronized,正是实现了后一种办法。

Synchronized

  1. 问:你平时涉及到多线程编程多不多?谈谈你对Synchronized锁的理解
  2. 分析:多从实现原理,工作机制来描述
  3. 答:
    1.   在多线程编程中,为了达到线程安全的目的,我们往往通过加锁的方式来实现。而Synchronized正是java提供给我们的非常重要的锁之一。它属于jvm级别加锁,底层实现是:在编译过程中,在指令级别加入一些标识来实现的。例如,同步代码块,会在同步代码块首尾加入monitorenter和monitorexit字节码指令,这两个指令都需要一个reference类型的参数,指明要加锁和解锁的对象,同步方法则是通过在修饰符上加acc_synchronized标识实现。在执行到这些指令(标识)时,本质都是获取、占有、释放monitor锁对象实现互斥,也就是说,同一时刻,只能有一个线程能成功的获取到这个锁对象。我们看一段加了synchronized关键字的代码编译后的字节码。编译前:

      1 public class test {
      2 public test() {
      3 }
      4 public static void main(String[] args) {
      5 synchronized(new Object()){
      6 int i = 0;
      7 }
      8 }
      9 }

      编译后:

      public class test extends java.lang.Object{
      public test();
      Code:
      0: aload_0
      1: invokespecial #1; //Method java/lang/Object."":()V
      4: nop
      5: return public static void main(java.lang.String[]);
      Code:
      0: new #2; //class Object
      3: dup
      4: invokespecial #1; //Method java/lang/Object."":()V
      7: dup
      8: astore_1
      9: monitorenter // Enter the monitor associated with object
      10: iconst_0
      11: istore_2
      12: nop
      13: aload_1
      14: monitorexit // Exit the monitor associated with object
      15: goto 23
      18: astore_3
      19: aload_1
      20: monitorexit // Be sure to exit monitor...
      21: aload_3
      22: athrow
      23: nop
      24: return
      Exception table:
      from to target type
      10 15 18 any
      18 21 18 any }

      重点关注14行,和20行。

    2.  在使用Synchronized时,用到的方法是wait和notify(或notifyAll),他们的原理是,调用wait方法后,线程让出cpu资源,释放锁,进入waiting状态,进入等待队列【第一个队列】。当有其他线程调用了notify或者notifyAll唤醒时,会将等待队列里的线程对象,移入阻塞队列【第二个队列】,状态是blocked,等待锁被释放后(这个释放时机,由虚拟机来决定,人为无法干预),开始竞争锁。
    3. Synchronized无法中断正在阻塞队列或者等待队列的线程。

  4.扩展:Synchronized提供了以下几种类型的锁:偏向锁、轻量级锁、重量级锁。在大部分情况下,并不存在多线程竞争,更常见的是一个线程多次获取同一个锁。那么很多的消耗,其实是在锁的获取与释放上。Synchronized一直在被优化,可以说Synchronized虽然推出的较早,但是效率并不比后来推出的Lock差。

  1.  偏向锁:在jdk1.6中引入,目的是消除在无竞争情况下的同步原语(翻译成人话就是,即使加了synchronized关键字,但是在没有竞争的时候,没必要去做获取-持有-释放锁对象的操作,提高程序运行性能)。怎么做呢?当锁对象第一次被线程A获取时,虚拟机会把对象头中的标志位设置为01,也就是代表偏向模式。同时把代表这个线程A的ID,通过CAS方式,更新到锁对象头的MarkWord中。相同的线程下次再次申请锁的时候,只需要简单的比较线程ID即可。以上操作成功,则成功进入到同步代码块。如果此时有其他线程B来竞争该锁,分两种情况做不同的处理:
    1. 如果线程A已执行完(并不会主动的修改锁对象的状态),会直接撤销锁对象的状态为未锁定,标志位为00;
    2. 如果线程A还在持有该锁,则锁升级为轻量级锁。  
  2. 轻量级锁:也是JDK1.6中引入的,轻量级,是相对于使用互斥量的重量级锁来说的。线程发生竞争锁的时候,不会直接进入阻塞状态,而是先尝试做CAS修改操作,进入自旋,这个过程避免了线程状态切换的开销,不过要消耗cpu资源。详细过程是:
    1.   线程尝试进入同步代码块,如果锁对象未被锁定,在当前线程对应的栈帧中,建立锁记录的空间,用于存储锁对象Mark Word的拷贝。
    2. 然后JVM用CAS方式尝试将锁对象的MarkWord内容替换为指向前述“锁记录”的指针。如果成功,当前线程则持有了锁,处于轻量级锁定状态;如果失败,会首先检查当前MarkWord是否已经指向当前线程栈帧的“锁记录”,如果是,就说明当前线程已经拥有了这个锁,直接重入即可。否则就表明是其他线程持有锁,那么进入自旋(其实就是重试CAS修改操作)。
    3. 释放锁时,是使用CAS来讲MarkWord和“锁记录”里的内容互换。如果成功,成功释放;如果事变,表明当前锁存在竞争(被其他线程修改了MarkWord里的数据),此时,锁会升级为重量级锁。
  3. 重量级锁:也就是我们使用的互斥量方式实现的锁,当存在多线程竞争时,只要没拿到锁,就会进入阻塞状态,主要消耗是在阻塞-唤起-阻塞-唤起的线程状态切换上。
  4. 上面介绍的三种类型的锁,是JVM来负责管理使用哪种类型锁,以及锁的升级(注意,没有降级)。
  5. 这里涉及到锁升级,对象头MarkWord等内容,如果详细说,可能又是一大篇文章了,如果大家感兴趣,可以另起一篇。
  6. synchronized就先介绍到这里,下一篇预告:ReentrantLock相关
  7. 如果你看的爽,请点击右下角的“推荐”,是对小端坚持分享原创的最大鼓励。也可以关注小端的个人公众号 :   pnxsxb  ,会分享更多的原创技术文章。

欢迎扫描以下二维码:

BAT美团滴滴java面试大纲(带答案版)之三:多线程synchronized的更多相关文章

  1. BAT美团滴滴java面试大纲(带答案版)之三:多线程Lock

    继续面试大纲系列文章. 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸芸众生:而滥用则会遭其反噬. 在多线程编程中要渡的第二个“劫”,则是Lock.在很多时候, ...

  2. 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇

    Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...

  3. BAT美团滴滴java面试大纲(带答案版)之四:多线程Lock

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 这是多线程的第二篇. 多线程就像武学中对的吸星大法,理解透了用好了可以得道成仙,俯瞰芸 ...

  4. Java面试大纲-java面试该做哪些准备,java开发达到这样的水平可以涨工资

    Java培训结束,面临的就是毕业找工作.在找工作时,就要针对性地做充分的面试准备.准备不充分的面试,完全是浪费时间,更是对自己的不负责. 上海尚学堂Java培训整理出Java面试大纲,其中大部分都是面 ...

  5. 2019滴滴java面试总结 (包含面试题解析)

    2019滴滴java面试总结  (包含面试题) 本人6年开发经验.今年年初找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.滴滴等公司offer,岗位是既有php也有Java后端开发,最终选择去了滴滴 ...

  6. Java面试宝典(2018版)

    置顶 2018年11月10日 23:49:18 我要取一个响亮的昵称 阅读数:8893    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/chen ...

  7. Java面试:投行的15个多线程和并发面试题

    多线程和并发问题已成为各种 Java 面试中必不可少的一部分.如果你准备参加投行的 Java 开发岗位面试,比如巴克莱银行(Barclays).花旗银行(Citibank).摩根史坦利投资公司(Mor ...

  8. Java面试:投行的15个多线程和并发面试题(转)

    多线程和并发问题已成为各种 Java 面试中必不可少的一部分.如果你准备参加投行的 Java 开发岗位面试,比如巴克莱银行(Barclays).花旗银行(Citibank).摩根史坦利投资公司(Mor ...

  9. 2019 滴滴java面试笔试总结 (含面试题解析)

       本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.滴滴等公司offer,岗位是Java后端开发,因为发展原因最终选择去了滴滴,入职一年时间了,也成为了面试官, ...

随机推荐

  1. Scrapy 为每一个Spider设置自己的Pipeline

    settings中的ITEM_PIPELINES 通常我们需要把数据存在数据库中,一般通过scrapy的pipelines管道机制来实现.做法是,先在pipelines.py模块中编写Pipeline ...

  2. Python 反射机制之hasattr()、getattr()、setattr() 、delattr()函数

    反射机制 先看看我对Java中反射机制的通俗理解:反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化 ...

  3. 前后端分离djangorestframework——版本控制组件

    什么是版本控制 在实际开发中,随着时间的更新迭代,我们维护的项目可能会有很多个版本,所以我们写的API也有很多个版本,但是迭代到高版本,不可能以前的版本就不用了,比如一个手机端的app,不定期发布新版 ...

  4. 给html标签加上鼠标划过小手样式

    给html标签加上鼠标划过小手样式 方法:给当前标签增加样式 style="cursor:pointer;" eg:增加返回箭头样式,给箭头增加小手 <span onclic ...

  5. xss挑战之旅wp

    Level 1  -  180831 第一关很简单,开胃菜 payload: http://localhost/xss_game/level1.php?name=test123<script&g ...

  6. netsh winsock reset命令,作用是重置 Winsock 目录

    Win xp重置 编辑 要为 Windows XP 重置 Winsock,请按照下列步骤操作: 1.单击“开始”,运行中输入cmd. 2.然后输入命令 netsh winsock reset. 3.重 ...

  7. MATLAB一元线性回归分析

    MATLAB一元线性回归分析应用举例 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ huigui.m function [b,bint,r,rint, ...

  8. python3编写网络爬虫23-分布式爬虫

    一.分布式爬虫 前面我们了解Scrapy爬虫框架的基本用法 这些框架都是在同一台主机运行的 爬取效率有限 如果多台主机协同爬取 爬取效率必然成倍增长这就是分布式爬虫的优势 1. 分布式爬虫基本原理 1 ...

  9. SecureCRT8.1+SecureCRT_keygen完成注册

    原文:https://www.cnblogs.com/qiyawei/p/7822957.html 1.下载完secureCRT8.1之后,进行安装. 点击secureCRT.exe的时候会出现如下图 ...

  10. Spring Web项目spring配置文件随服务器启动时自动加载

    前言:其实配置文件不随服务器启动时加载也是可以的,但是这样操作的话,每次获取相应对象,就会去读取一次配置文件,从而降低程序的效率,而Spring中已经为我们提供了监听器,可监听服务器是否启动,然后在启 ...