什么?面试官问我Java内存模型!这不得给我加薪?,2024年最新java的面试题库

内存模型的抽象结构


image

  • 共享变量

共享变量手内存模型影响,线程会去主内存里去加载共享变量,当线程需要改变共享变量时,会将本地内存已更改的副本提交到主内存.

  • 局部变量

局部变量不会受内存模型的影响

线程之间通信

image

指令重排

  • 编译器优化的重排序

  • 指令级并行的重排序

  • 内存系统的重排序

image

什么是指令重排?


int i=0; 2 int j=1;

按照我们的认知,程序是一行一行往下执行的,但是由于编译器或运行时环境为了优化程序性能,采取对指令进行重新排序执行,也就是说在计算机执行上面两句话的时候,有可能第二条语句会优先于第一条语句执行.

然而并不是所有的指令都能重排,重排需要基于数据依赖性.

数据依赖性

如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。数据依赖分下列三种类型:

| 名称 | 代码示例 | 说明 |

| — | — | — |

| 写后读 | a=1;b=a; | 写一个变量之后,再读这个位置. |

| 写后写 | a=1;a=2; | 写一个变量之后,再写这个变量. |

| 读后写 | a=b;b=1; | 读一个变量之后,再写这个变量. |

上面的情况,如果重排序了两个操作的执行顺序,程序的执行结果将会跟预期完全不一样.

所以说,虽然编译器和处理器可能会对操作做重排序,但是编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。

注意,这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。

as-if-serial

定义:不管怎么重排序(编译器和处理器为了提⾼并⾏度),(单线程) 程序的执⾏结果不能被改变。编译器、runtime和处理器都必须遵守as-if-serial语义。

image

happens-before

happens-before是JMM的最核心概念之一

JMM设计意图


  • 程序员对内存模型的使用

  • 为程序员提供足够强的内存可见性保证

  • 编译器和处理器对内存模型的实现

  • 对编译器和处理器的限制要尽可能的放松

JMM禁止:

禁止编译器和处理器会改变程序执行结果的重排序.

JMM允许:

允许编译器和处理器不会改变程序执行结果的重排序.

happens-before规则

在JMM中,如果⼀个操作执⾏的结果需要对另⼀个操作可⻅,那么这两个操作之间必须要存在happens-before关系.

  • 程序顺序规则  ⼀个线程中的每个操作,happens-before于该线程中的任意后续操作.

  • 监视器锁规则  对⼀个锁的解锁,happens-before于随后对这个锁的加锁.

  • volatile变量规则  对⼀个volatile域的写,happens-before于任意后续对这个volatile域的读.

  • 传递性  如果A happens-before B,且B happens-before C,那么A happens-before C.

  • start()规则  如果线程A执⾏操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。

  • join()规则  如果线程A执⾏操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()返回

  • 线程中断规则  对线程interrupt⽅法的调⽤happens-before于被中断线程的代码检测到中断事件的发⽣.

  • 对象终结规则  ⼀个对象的初始化的完成,也就是构造函数执⾏的结束⼀定 happens-before它的finalize()⽅法.

JMM向程序员提供的happens-before规则能满⾜程序员的需求.


JMM对编译器和处理器的束缚已经尽可能少.

JMM对程序员的承诺


如果⼀个操作happens-before另⼀个操作,那么第⼀个操作的执⾏结果将对第⼆个操作 可⻅,⽽且第⼀个操作的执⾏顺序排在第⼆个操作之前.

JMM对编译器和处理器重排序的约束原则


两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照 happens-before关系指定的顺序来执⾏.

例子:

1 public class Demo29 {

2 int a=0;

3 boolean flag=false;

4 public void writer(){

5 a=1; //1

6 flag=true; //2

7 }

8 public void reader(){

9 if(flag){ //3

10 int i=a * a; //4

11 }

12 }

13 }

假如线程B在进行操作4时,能否看到线程A在操作1对共享变量a的写入呢? 不一定

| 时刻 | 线程A | 线程B |

| T1 | flag=true | |

| T2 | | if(flag) |

| T3 | | int i=a*a |

| T4 | a=1 | |

当线程A在执行writer方法时,因为指令重排序,会先执行flag=true,再执行a=1.而线程B在执行操作4时就会读不到线程A对共享变量a的写入,导致运行结果超出预期.

解决方案1:

通过加锁的方式来解决

1 public class Demo29 {

2 int a=0;

3 boolean flag=false;

4 public synchronized void writer(){

5 a=1; //1

6 flag=true; //2

7 }

8 public synchronized void reader(){

9 if(flag){ //3

10 int i=a * a; //4

11 }

12 }

13 }

image

锁的内存语义:

image

  • 线程A释放⼀个锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了(线程A 对共享变量所做修改的)消息。

  • 线程B获取⼀个锁,实质上是线程B接收了之前某个线程发出的(在释放这个锁之前对共 享变量所做修改的)消息。

  • 线程A释放锁,随后线程B获取这个锁,这个过程实质上是线程A通过主内存向线程B发 送消息。

volatile的作用


  1. volatile原理:被volatile关键字修饰的变量,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

  2. 在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制。当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。

  3. volatile在Java并发编程中常用于保持内存可见性和防止指令重排序。内存可见性(Memory Visibility):所有线程都能看到共享内存的最新状态;防止指令重排:在基于偏序关系的Happens-Before内存模型中,指令重排技术大大提高了程序执行效率,但同时也引入了一些问题。

  4. 可见性:volatile保持内存可见性的特殊规则:read、load、use动作必须连续出现;assign、store、write动作必须连续出现;每次读取前必须先从主内存刷新最新的值;每次写入后必须立即同步回主内存当中。也就是说,volatile关键字修饰的变量看到的随时是自己的最新值。在线程1中对变量v的最新修改,对线程2是可见的。

  5. 内存屏障:volatile防止指令重排的策略:在每个volatile写操作的前面插入一个StoreStore屏障;在每个volatile写操作的后面插入一个StoreLoad屏障;在每个volatile读操作的后面插入一个LoadLoad屏障;在每个volatile读操作的后面插入一个LoadStore屏障。

  6. volatile 性能:volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。


volatile内存语义

image

  • 线程A写⼀个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程 发出了(其对共享变量所做修改的)消息。

  • 线程B读⼀个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile 变量之前对共享变量所做修改的)消息。

  • 线程A写⼀个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过 主内存向线程B发送消息。

volatile内存语义的实现

| 是否能重排序 | 第二个操作 |

| — | — |

| 第一个操作 | 普通读/写 |

| 普通读/写 | Y |

| volatile读 | N |

| volatile写 | Y |

  • 当第⼆个操作是volatile写时,不管第⼀个操作是什么,都不能重排序。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。

**另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 **

下面有部分截图希望能对大家有所帮助。

在这里插入图片描述

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。

**另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 **

下面有部分截图希望能对大家有所帮助。

[外链图片转存中…(img-KArj3WzQ-1712966954358)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-Azt5KyVI-1712966954358)]

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java二级证书是Oracle公司认可的一种Java技能认证证书,证明了持证者具备Java语言基础知识和应用能力。获得Java二级证书可以证明个人在Java开发方面的专业技能和能力,可以提升求职者的竞争力,也有助于现有Java开发人员的职业发展。此外,Java二级证书还是许多企业用于评价Java开发人员技能水平的重要参考标准之一。 ### 回答2: Java二级证书是指通过Oracle官方认证考试所获得的证书,具有很大的实用价值。主要用途如下: 1. 增强求职竞争力:Java二级证书是衡量一个软件开发人员Java编程技能的重要标准,具备该证书可以在众多求职者中脱颖而出,提高求职竞争力。 2. 提升工作能力:Java二级证书考试内容系统而全面,涵盖了Java的各个方面,通过自学备考和考试,可以使考生更全面地理解和掌握Java编程语言,从而提升工作中的开发能力和效率。 3. 证明专业素质:Java二级证书的获得,可以证明持证人在Java编程方面具备扎实的理论基础和实际操作能力,体现了个人的专业素质和学习能力,为个人的职业发展打下坚实的基础。 4. 提供职业发展机会:获得Java二级证书后,可以进一步提高个人在软件开发领域的职业地位,获取更好的职业发展机会,例如晋升、加薪、跳槽等,为个人的职业发展提供更广阔的空间。 5. 参与项目竞标:在软件开发项目竞标中,Java二级证书是很多企业和组织希望招募合格人员的必备条件之一,持有该证书可以增加项目竞标的成功率,为个人带来更多的机会和收益。 因此,Java二级证书不仅对于个人在求职中具有重要意义,同时也对个人的职业发展和专业素质提升有很大的帮助和作用。 ### 回答3: Java二级证书是由Oracle公司颁发的一种专业技能认证证书。持有该证书意味着证书持有人在Java编程领域具备较高的技术水平和专业能力。具体而言,Java二级证书的用途主要包括以下几个方面: 1. 提升就业竞争力:在当今信息技术迅速发展的环境下,具备专业认证的人才更有竞争力。Java二级证书可以证明持有人在Java编程方面具备扎实的理论基础和实际操作能力,因此可以帮助持证人在就业市场上脱颖而出。 2. 为个人职业发展提供支持:持有Java二级证书可以为个人职业发展提供有效的支持。证书持有人可以通过该证书证明自己的专业技术水平,提高个人在公司内部的职位升迁机会,也可以在其他公司或者项目中展示自己的专业能力,有助于扩大个人的发展空间。 3. 增加技术能力和知识储备:参加Java二级证书考试需要深入学习Java编程的理论知识和实践经验,因此通过考试获得证书的过程本身就是一种深化学习和提升技术能力的过程。持有该证书可以证明证书持有人在Java编程方面具备较高的技术能力和知识储备。 总之,Java二级证书是一种国际认可的专业技能认证,在就业、个人职业发展以及技术能力提升方面都有着重要的作用。它不仅可以提高持证人在就业市场的竞争力,也可以为个人职业发展提供有效的支持,同时还可以增加技术能力和知识储备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值