本文转载自【微信公众号:java进阶架构师,ID:java_jiagoushi】经微信公众号授权转载,如需转载与原文作者联系

开篇介绍

大家好,我是Java面试题库的提裤姐,今天这篇是JavaSE系列的第十一篇,主要总结了Java中的多线程问题,多线程分为三篇来讲,这篇是第三篇,在后续,会沿着第一篇开篇的知识线路一直总结下去,做到日更!如果我能做到百日百更,希望你也可以跟着百日百刷,一百天养成一个好习惯。

Q:

volatile关键字的作用?

对于可见性,Java提供了volatile关键字来保证可见性。当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。主要的原理是使用了内存指令。

LoadLoad重排序:一个处理器先执行一个L1读操作,再执行一个L2读操作;但是另外一个处理器看到的是先L2再L1StoreStore重排序:一个处理器先执行一个W1写操作,再执行一个W2写操作;但是另外一个处理器看到的是先W2再W1LoadStore重排序:一个处理器先执行一个L1读操作,再执行一个W2写操作;但是另外一个处理器看到的是先W2再L1StoreLoad重排序:一个处理器先执行一个W1写操作,再执行一个L2读操作;但是另外一个处理器看到的是先L2再W1

Q:

说一下volatile关键字对原子性、可见性以及有序性的保证?

在volatile变量写操作的前面会加入一个

Release

屏障,然后在之后会加入一个

Store

屏障,这样就可以保证volatile写跟Release屏障之前的任何读写操作都不会指令重排,然后Store屏障保证了,写完数据之后,立马会执行flush处理器缓存的操作。

在volatile变量读操作的前面会加入一个

Load

屏障,这样就可以保证对这个变量的读取时,如果被别的处理器修改过了,必须得从其他 处理器的高速缓存(或者主内存)中加载到自己本地高速缓存里,保证读到的是最新数据;在之后会加入一个

Acquire

屏障,禁止volatile读操作之后的任何读写操作会跟volatile读指令重排序。与volatie读写内存屏障对比一下,是类似的意思。

Acquire屏障

其实就是

LoadLoad屏障 + LoadStore屏障

Release屏障

其实就是

StoreLoad屏障 + StoreStore屏障

Q:

什么是CAS?

CAS(compare and swap)的缩写。Java利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法,实现原子操作。其它原子操作都是利用类似的特性完成的。 CAS有3个操作数:

内存值V

旧的预期值A

要修改的新值B

。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。CAS的缺点:

CPU开销过大在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。不能保证代码块的原子性CAS机制所保证的知识一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。ABA问题这是CAS机制最大的问题所在。

Q:

什么是AQS?

AQS,即AbstractQueuedSynchronizer,

队列同步器

,它是Java并发用来构建锁和其他同步组件的基础框架。

同步组件对AQS的使用: AQS是一个抽象类,主是是以继承的方式使用。AQS本身是没有实现任何同步接口的,它仅仅只是定义了同步状态的获取和释放的方法来供自定义的同步组件的使用。查看源码可知,在java的同步组件中,AQS的子类(Sync等)一般是同步组件的静态内部类,即通过组合的方式使用。 抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch 它维护了一个volatile int state(代表共享资源)和一个FIFO(双向队列)线程等待队列(多线程争用资源被阻塞时会进入此队列)

1public class CountDownLatch {2 /** 3 * Synchronization control For CountDownLatch. 4 * Uses AQS state to represent count. 5 */ 6 private static final class Sync extends AbstractQueuedSynchronizer { 7 private static final long serialVersionUID = 4982264981922014374L; 8 9 Sync(int count) {10 setState(count);11 }1213 int getCount() {14 return getState();15 }1617 protected int tryAcquireShared(int acquires) {18 return (getState() == 0) ? 1 : -1;19 }2021 protected boolean tryReleaseShared(int releases) {22 // Decrement count; signal when transition to zero23 for (;;) {24 int c = getState();25 if (c == 0)26 return false;27 int nextc = c-1;28 if (compareAndSetState(c, nextc))29 return nextc == 0;30 }31 }32 }33}

Q:

Semaphore是什么?

Semaphore就是一个信号量,它的作用是限制某段代码块的并发数。 semaphore有一个构造函数,可以传入一个int型整数n,表示某段代码最多只有n个线程可以访问,如果超出了n,那么请等待,等到某个线程执行完毕这段代码块,下一个线程再进入。由此可以看出如果Semaphore构造函数中传入的int型整数n=1,相当于变成了一个synchronized了。

1public static void main(String[] args) { 2 int N = 8; //工人数 3 Semaphore semaphore = new Semaphore(5); //机器数目 4 for(int i=0;i

Q:

Synchronized的原理是什么?

Synchronized是由JVM实现的一种实现互斥同步的方式,查看被Synchronized修饰过的程序块编译后的字节码,会发现,被Synchronized修饰过的程序块,在编译前后被编译器生成了

monitorenter

monitorexit

两个字节码指令。在虚拟机执行到monitorenter指令时,首先要尝试获取对象的锁:如果这个对象没有锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数器+1;当执行monitorexit指令时,将锁计数器-1;当计数器为0时,锁就被释放了。如果获取对象失败了,那当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。Java中Synchronize通过在对象头设置标志,达到了获取锁和释放锁的目的。

Q:

为什么说Synchronized是非公平锁?

非公平主要表现在获取锁的行为上,并非是按照申请锁的时间前后给等待线程分配锁的,每当锁被释放后,任何一个线程都有机会竞争到锁,这样做的目的是为了提高执行性能,缺点是可能会产生线程饥饿现象。

Q:

JVM对java的原生锁做了哪些优化?

在Java6之前, Monitor的实现完全依赖底层操作系统的互斥锁来实现.

由于Java层面的线程与操作系统的原生线程有映射关系,如果要将一个线程进行阻塞或唤起都需要操作系统的协助,这就需要从用户态切换到内核态来执行,这种切换代价十分昂贵,很耗处理器时间,现代JDK中做了大量的优化。一种优化是使用

自旋锁

,即在把线程进行阻塞操作之前先让线程自旋等待一段时间,可能在等待期间其他线程已经解锁,这时就无需再让线程执行阻塞操作,避免了用户态到内核态的切换。现代JDK中还提供了三种不同的 Monitor实现,也就是三种不同的锁:

偏向锁(Biased Locking)轻量级锁重量级锁这三种锁使得JDK得以优化 Synchronized的运行,当JVM检测到不同的竞争状况时,会自动切换到适合的锁实现,这就是锁的升级、降级。当没有竞争出现时,默认会使用偏向锁。JVM会利用CAS操作,在对象头上的 Mark Word部分设置线程ID,以表示这个对象偏向于当前线程,所以并不涉及真正的互斥锁,因为在很多应用场景中,大部分对象生命周期中最多会被一个线程锁定,使用偏向锁可以降低无竞争开销。如果有另一线程试图锁定某个被偏向过的对象,JVM就撤销偏向锁,切换到轻量级锁实现。轻量级锁依赖CAS操作 Mark Word来试图获取锁,如果重试成功,就使用普通的轻量级锁否则,进一步升级为重量级锁。

Q:

Synchronized和 ReentrantLock的异同?

synchronized:是java内置的关键字,它提供了一种独占的加锁方式。synchronized的获取和释放锁由JVM实现,用户不需要显示的释放锁,非常方便。然而synchronized也有一些问题:当线程尝试获取锁的时候,如果获取不到锁会一直阻塞。如果获取锁的线程进入休眠或者阻塞,除非当前线程异常,否则其他线程尝试获取锁必须一直等待。

ReentrantLock:ReentrantLock是Lock的实现类,是一个互斥的同步锁。ReentrantLock是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。等待可中断避免,出现死锁的情况(如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false) 公平锁与非公平锁多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

从功能角度:ReentrantLock比 Synchronized的同步操作更精细(因为可以像普通对象一样使用),甚至实现 Synchronized没有的高级功能,如:

等待可中断当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,对处理执行时间非常长的同步块很有用。带超时的获取锁尝试在指定的时间范围内获取锁,如果时间到了仍然无法获取则返回。可以判断是否有线程在排队等待获取锁。可以响应中断请求与Synchronized不同,当获取到锁的线程被中断时,能够响应中断,中断异常将会被抛出,同时锁会被释放。可以实现公平锁。从锁释放角度:Synchronized在JVM层面上实现的,不但可以通过一些监控工具监控 Synchronized的锁定,而且在代码执行出现异常时,JVM会自动释放锁定,但是使用Lock则不行,Lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中。

从性能角度:Synchronized早期实现比较低效,对比 ReentrantLock,大多数场景性能都相差较大。但是在Java6中对其进行了非常多的改进,在竞争不激烈时:Synchronized的性能要优于 ReetrantLock;在高竞争情况下:Synchronized的性能会下降几十倍,但是 ReetrantLock的性能能维持常态。

java+queue+se_「013期」JavaSE面试题(十三):多线程(3)相关推荐

  1. string s = new string(“xyz“);创建了几个对象_「005」-JavaSE面试题(五):String类

    第一期:Java面试 - 100题,梳理各大网站优秀面试题.大家可以跟着我一起来刷刷Java理论知识 [005] - JavaSE面试题(五):String类 第1问:String.StringBuf ...

  2. 今日头条php面试经验,「今日头条」前端面试题和思路解析

    一篇文章和一道面试题 作者用一道2017年「今日头条」的前端面试题为引子,分步讲解了最终结果的执行原因.其中涉及到了不少概念,比如异步的执行顺序,宏任务,微任务等等,同时作者限定了执行范围,以浏览器的 ...

  3. Java学习之「Spring + AspectJ 」

    目录 ■前言 ■省略部分 ■代码构造 ■运行效果 ■具体代码 AspectTest MyAspect   ★★★ @Aspect AppConf   ★★★ @EnableAspectJAutoPro ...

  4. java jxl poi_「excle下载」java实现下载excle(jxl、poi 两种方式) - seo实验室

    excle下载 @requestMAPPing(value="/download_index") public String downloadexcel(HttpServletRe ...

  5. java 连接oracle_「事件驱动架构」使用GoldenGate创建从Oracle到Kafka的CDC事件流

    我们通过GoldenGate技术在Oracle DB和Kafka代理之间创建集成,该技术实时发布Kafka中的CDC事件流. Oracle在其Oracle GoldenGate for Big Dat ...

  6. 类似婚礼纪的Java项目_「婚礼纪」婚礼纪 java面试 - seo实验室

    婚礼纪 我现在只是一个快2年经验的平凡的菜鸡boy 第一面架构师面试 1.简单介绍一下你经常使用的集合 3.arraylist和linklist的区别 4.map有用过吧,简单说一下 5.说一下Has ...

  7. arraylist java 排序_「arraylist排序」java ArrayList的两种排序方法 - seo实验室

    arraylist排序 1.ArrayList使用排序的初衷 我们知道ArrayList的好处是可以不用限定容器的大小,他会根据元素的增加自己扩大.但是存储进去的数据类型都会变成object,虽然每个 ...

  8. java 网络 io流_【015期】JavaSE面试题(十五):网络IO流

    什么是bio 同步阻塞式IO,服务端创建一个ServerSocket,然后客户端用一个Socket去连接那个ServerSocket,然后ServerSocket接收到一个Socket的连接请求就创建 ...

  9. 百姓大药房JAVA面试_「老百姓大药房面试|面试题」-看准网

    匿名用户 面试了职位:公关经理 面试未通过看似无比专业的面试,其实呵呵的操作 首先我是今年正月16去的面试,面试开始给人一种无比专业的现象.还需要做一套智商测试题,对测试你智商的答卷,还有星座问答(说 ...

最新文章

  1. html css 布局知识概况
  2. 虚拟机迁移及虚拟机高可用方案
  3. java get key_java – KeyStore getKey()在Android中返回null
  4. django html 模板继承,Django模板的继承
  5. zTree 优秀的jquery树插件
  6. 【HIbernate异常】could not initialize proxy - no Session (已解决)
  7. Python零基础入门(五)——文本文件读写和操作[学习笔记]
  8. 如何让电脑产生和输出特定分贝值的声音
  9. 2D武侠游戏《剑侠世界》网游单机 搭建教程说明
  10. ai背景合成_AI突破次元壁又火了!飞屋环游记动漫角色一秒变真人,网友:小罗的“猫王发型”有点酷...
  11. 有理数加法C语言pta,有理数
  12. “3D 元宇宙技术”在汽车新零售领域的应用与实践
  13. idou老师教你学istio :基于角色的访问控制
  14. 一个文献代理和医学资料非常丰富的地方
  15. 骑行、318总结心得啊经验什么的
  16. 网页上的文字不能复制怎么办?
  17. 如何把两个文件合并成pdf文件?
  18. 算法训练--最小公倍数
  19. win10打开程序响应很慢_win10优化设置最全教程(上)。
  20. 教你如何用UltraISO制作U盘系统安装盘(图文教程)

热门文章

  1. lopa分析_【风险分析方法】HAZOP、LOPA和FMEA三种分析方法,如何做到信息共享?...
  2. perl数组硬引用_perl引用和数组 - SibylY的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. 【控制】《复杂运动体系统的分布式协同控制与优化》-方浩老师-第1章-绪论
  4. 【控制】《多智能体系统一致性协同演化控制理论与技术》纪良浩老师-第10章-二阶离散时间时延多智能体系统加权一致性
  5. 图像的zoomfft变换
  6. mybaitis 通过Mapping 实现多表查询
  7. XML::Simple与Data::Dumper在Perl中的使用
  8. Stefan Tilkov:跳过单体应用,从微服务开始
  9. SpringQuartz定时任务调度器
  10. Wcf 接收对http://*.*.*.*的的 HTTP 响应时发生错误... 的解决方法