并发编程面试题绝命30问

一.请谈一下你对volatile的理解?

这个主要是往3个方面来谈;
1.1 谈一谈volatile 的特性
volatile 主要是实现了 可见性,禁止指令重排序,和单原子性。
1.2 它是怎么实现可见性的?
首先得知道 什么是可见性。打个比方,就拿买车票这件事来说吧 。有一个代表车票数量的变量 int count=20 由 售票员来代表共享内存 , 有小红 和小明 分别代表两个线程。小红先到的 先把知道还有20张票, 买了一张 20-1 。这时候小明也来了 他也要买车票 。而他俩是线程不安全的 ,小明不管小红有没有买完车票,他就要买。 而小红这边20已经减了1了, 但是还没有告诉给售票员。那就会出现小明这边也拿到的是一个20 。最终出现小明这边20-1 ,小红这边也20-1 票实际上是卖了两张 ,但是最终还剩19张票的情况。 这就是他们之间的不可见性。
而volatile解决的就是 做到了两步,
第一步 ,让小红的买完票的结果告诉给售票员,(私有变量写回共享内存)
第二步,告诉小明 等 现在票已经减1啦 不是20啦(通过MESI协议实现的)
volatile提供的内存语义:写、读操作内存语义,相当于锁的释放与获取
写操作
volatile a = 1;
内存屏障:ll/ls/ss/sl
x86 sfence/lfence/mfence
lock前缀
读操作
本地内存中的副本无效了,重新去内存中读取
!https://www.scss.tcd.ie/Jeremy.Jones/vivio/caches/MESIHelp.htm(MESI协议动画演示网址)
1.3禁止指令重排序又是个什么鬼?
这个要涉及到编译器优化,cpu级别的优化。我们的程序看起来是按照顺序执行的。其实编译器在编译的时候会对我们的程序做一些优化,比如说类似于没有io操作的赋值比有io 操作的代码行优先执行什么的。单线程遵循as-if-serial原则 ,多线程遵循happends-beffo 原则。这也有可能会导致线程不安全问题。
as-if-serial:
在这里插入图片描述
1.4 单原子性是指的是对于一个共享变量的一次操作是原子性的。(对于i++这种就无法保证其原子性)
1.5volatile的应用:
共享成员变量,用来做线程间的通信与同步。
j.u.c成员类:aqs、atomicInteger、ConcurrentHashMap、CopyOnWriteArrayList

二.DCL(Double Check Lock)单例为什么要加volatile?

这个先要说 这个是指的是单例模式双重检查模式
先来看一份代码:
volatile User user;
public User getInstance(){
if(user == null){
synchrnized(this){
if(user == null){
user = new User();
}
}
}
return user;
}
这段代码的意思是 在并发情况下有可能有一个线程已经成功new 了一个user 但是第二个线程有可能并没有看到new出来的User 所以他也会new 一个 这是这里要加一个synchrnized原因,
还有一个问题 。这个问题就涉及到 一个对象创建的过程
大致分为 ,
1.检查类有没有加载
2.为对象非配空间
3.讲引用写回桟
(当然具体细节不止这3步具体看对象的创建过程)
这个是因为 对象创建过程这件事本身他不是有序进行的 cpu 可以先把引用写回桟 然后再进行空间的分配。所以这时候 会导致不同的线程间,去访问新new 出来的User的时候 可能会出现引用存在 但是实例确不能使用的情况。(当然单线程是没问题的)

三.CAS是什么?

全称是 Compare And Swap 比较并替换。
可以简单的说 是一种乐观锁的一种实现
线程A 是 把共享变量 拿到本地内存后 先保存个原有值,再去改一个预期值,当把私有变量写回公共内存时先进行比较,原有值不变就把预期值写进去,原有值发现已经变了 ,那就自旋。
举个例子,还是小明去买票,先把共享变量拿到本地。此时小明多做一个动作,我先记住我刚问票的时候的数量是20,我先在这个基础上进行-1 。当我付账的时候,我不是直接 付,我先拿我记住的库存和现有的的库存比较,还是不是20,如果已经不是20了。 那我就再来一遍。

四.CAS的ABA问题如何解决?

先搞清楚,啥是ABA问题。
还是买票的例子,小红买了一张票,小明也买了张票 ,他俩都没结账(没写回共享内存) 但是小红觉得她又不想走了,她又把票退了,这个时候小明结账的时候发现数量是对的 。但是,但是什么呢。这中间小红明明也操作了一下,那怎么让小明知道他买的这张票是小红退掉的那张呢。这就是ABA问题。
解决这个问题一般的方法是加版本号。或者有个标记 ture 或false 去专门标记这个共享变量是不是原始数据。

五.请谈一下AQS,为什么AQS的底层是CAS+volatile?

AQS是一个同步器,他的本质思想是通过cas 操作一个volatile的变量state 来实现同步。
而又 因为volatile能实现线程间的可见性 保证了这个state标志是线程安全的 CAS 则保证线程在不阻塞,通过自旋的方式去访问这个变量

六.你都用过哪些AQS实现的同步组件?

Lock ReentrantLock:
state 0 -1 -2 -3 只要是不等于0,就表示锁没有被释放。
ReadWriteReentrantLock:
拆分 16位一拆,高16位表示读锁、低16位表示写锁。
CountDownLatch:
count,倒计时,countDown -1;
CyclicBarrier:
初始值为0,指定的parities,只允许增加,满足了parities又开始新的一轮。
Semaphore:
n,获取锁的 -1&#x

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值