记一次Java面试问题点总结
引言
昨日接了一个阿里外包的电话面试,问了一些技术问题感觉到自己是真的菜,接触Java开发已经也有一段时间,技术方面说来惭愧,一直以来只是局限于框架工具的用法,也没有进行了解其实现的原理,更重要的是一直没有归纳和总结,这次把这些问题记录下来,相关的知识点也找了一些资料学习下。
问题
1. CountDownLanch的工作原理
实现原理:计数器的值由构造函数传入,并用它初始化AQS的state值。当线程调用await方法时会检查state的值是否为0,如果是就直接返回(即不会阻塞);如果不是,将表示该节点的线程入列,然后将自身阻塞。当其它线程调用countDown方法会将计数器减1,然后判断计数器的值是否为0,当它为0时,会唤醒队列中的第一个节点,由于CountDownLatch使用了AQS的共享模式,所以第一个节点被唤醒后又会唤醒第二个节点,以此类推,使得所有因await方法阻塞的线程都能被唤醒而继续执行。
引用别人的博客里的一段话,详细请点击:Java并发包中CountDownLatch的工作原理、使用示例
题外话:
什么是 AQS(抽象的队列同步器)
AbstractQueuedSynchronizer类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问 共享资源的同步器框架,许多同步类实现都依赖于它,如常用的 ReentrantLock/Semaphore/CountDownLatch。它维护了一个 volatile int state(代表共享资源)和一个 FIFO 线程等待队列(多线程争用资源被 阻塞时会进入此队列)。这里 volatile 是核心关键词,具体 volatile 的语义,在此不述。state 的 访问方式有三种: getState() setState() compareAndSetState()
AQS只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现,AQS这里只定义了一个 接口,具体资源的获取交由自定义同步器去实现了(通过state的get/set/CAS)之所以没有定义成 abstract,是因为独占模式下只用实现 tryAcquire-tryRelease,而共享模式下只用实现 tryAcquireShared-tryReleaseShared。如果都定义成abstract,那么每个模式也要去实现另一模 式下的接口。不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实 现共享资源 state 的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/ 唤醒出队等),AQS已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法:
1. isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。2. tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
3. tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
4. tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0 表示成功,但没有剩余 可用资源;正数表示成功,且有剩余资源。
5. tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回 true,否则返回false。
AQS定义两种资源共享方式
1.Exclusive独占资源 -ReentrantLock Exclusive(独占,只有一个线程能执行,如ReentrantLock)
2.Share共享资源 -Semaphore/CountDownLatch Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。
3.实现独占和共享两种 方式,一般来说,自定义同步器要么是独占方法,要么是共享方式,他们也只需实现 tryAcquiretryRelease、tryAcquireShared-tryReleaseShared 中的一种即可。但 AQS 也支持自定义同步器 同时实现独占和共享两种方式,如ReentrantReadWriteLock
同步器的实现是ABS核心,以ReentrantLock为例,state初始化为0,表示未锁定状态。A线程 lock()时,首先会调用compareAndSet(0,1)判断是否首次加锁,如果是首次则把当前线程记录下来,如果不是会调用 tryAcquire()中判断当前线程是否为独占线程,如果是独占该锁并将 state+1(可重入)。如果不是则返回false,此后,其他线程再 tryAcquire()时就会失 败,直到A线程unlock()到state=0(即释放锁)为止,其它线程才有机会获取该锁。当然,释放 锁之前,A 线程自己是可以重复获取此锁的(state 会累加),这就是可重入的概念。但要注意, 获取多少次就要释放多么次,这样才能保证state是能回到零态的。
以CountDownLatch以例,任务分为N个子线程去执行,state也初始化为N(注意N要与 线程个数一致)。这 N 个子线程是并行执行的,每个子线程执行完后 countDown()一次,state 会CAS减1。等到所有子线程都执行完后(即state=0),会unpark()主调用线程,然后主调用线程 就会从await()函数返回,继续后余动作。
2. 说一下自旋锁的原理
如果持有锁的线程能在很短的时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换,它们只需要等一等(自旋),等待锁释放之后即可立即获取锁,这样避免了用户线程和内核切换的消耗
线程自旋是需要消耗 cup 的,说白了就是让 cup 在做无用功,如果一直获取不到锁,那线程 也不能一直占用cup自旋做无用功,所以需要设定一个自旋等待的最大时间。
如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁 的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。自旋锁的优缺点
自旋锁尽可能的减少线程的阻塞,这对于锁的竞争不激烈,且占用锁时间非常短的代码块来 说性能能大幅度的提升,因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗,这些操作会 导致线程发生两次上下文切换!
但是如果锁的竞争激烈,或者持有锁的线程需要长时间占用锁执行同步块,这时候就不适合 使用自旋锁了,因为自旋锁在获取锁前一直都是占用 cpu 做无用功,占着 XX 不 XX,同时有大量 线程在竞争一个锁,会导致获取锁的时间很长,线程自旋的消耗大于线程阻塞挂起操作的消耗, 其它需要cup的线程又不能获取到cpu,造成cpu的浪费。所以这种情况下我们要关闭自旋锁;
3. synchronized中类锁和对象锁的区别
这么基础的一个问题我竟然遗忘了。。因为之前记的是锁static方法和非static方法的区别,其实锁static方法就相当于锁类class,因为static方法是所有的类共享的,类锁是锁当前类的所有实例,对象锁是锁当前实例对象,详细的引入别人的博客:Java锁Synchronized对象锁和类锁的区别
4. volatile关键字的作用
问:说下项目中用到的设计模式
答:单例模式、责任链模式、工程模式、模板模式等等
问:那你说下你们平常单例模式怎么实现的
答:我们用的是双向检查
问:你们双向检查有用到volatile吧,那你说下这个关键字有什么作用
答:它可以用来保证线程每次获取的对象都是最新状态
问:除此之外还有什么作用
答: 卒
真的是
记一次Java面试问题点总结的更多相关文章
- Java面试题精选(三) JSP/Servlet Java面试逻辑题
-- JSP/Servlet Java面试逻辑题 -- 很显然,Servlet/JSP的WEB前端动态制作的重要性比HTML/CSS/JS的价值高很多,但我们都知道他们都是建立在HT ...
- Java 面试宝典-2017
http://www.cnblogs.com/nelson-hu/p/7190163.html Java面试宝典-2017 Java面试宝典2017版 一. Java基础部分........... ...
- Java面试宝典-2017
Java面试宝典2017版 一. Java基础部分........................................................................... ...
- Java 面试知识点解析(三)——JVM篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- Java面试宝典2018
转 Java面试宝典2018 一. Java基础部分…………………………………………………………………………………….. 7 1.一个“.java”源文件中是否可以包括多个类(不是内部类)?有什么限制 ...
- Java面试总结(面试流程及核心面试题)
Java面试流程及核心面试题 面试整体流程 1.1 简单的自我介绍 我是xxxx,工作xxx年.我先后在xxxx公司.yyyy公司工作.先后做个xxxx项目.yyyy项目. 1.2 你简单介 ...
- Java面试准备十六:数据库——MySQL性能优化
2017年04月20日 13:09:43 阅读数:6837 这里只是为了记录,由于自身水平实在不怎么样,难免错误百出,有错的地方还望大家多多指出,谢谢. 来自MySQL性能优化的最佳20+经验 为查询 ...
- Java面试总结 Boss沟通过:500+,面试:20,已投简历130+
1 概述 1 介绍 最近换工作,对最近面试的过程进行总结,总结每个公司的面试流程和问到的面试题,记录自己,也供大家参考. 我是一名Java开发,工作经验10年,所以面试一名高级Java开发工程师. 简 ...
- JAVA面试中问及HIBERNATE与 MYBATIS的对比,在这里做一下总结
我是一名java开发人员,hibernate以及mybatis都有过学习,在java面试中也被提及问道过,在项目实践中也应用过,现在对hibernate和mybatis做一下对比,便于大家更好的理解和 ...
随机推荐
- Liunx用户运行模式
运行模式也可以称之为运行级别(Running Level). 在linux中存在一个进程:init (initialize,初始化),进程id是1. [he@localhost ~]$ ps -ef ...
- [YOLO]《YOLOv3: An Incremental Improvement》笔记
相比较于前两篇论文,个人感觉YOLO3作者有点来搞笑的!!!虽然加了一些新的点子进来,但是,论文的开头是这样的: 简单理解就是作者花了很多时间玩Twitter去了,所以没有做啥研究!!!! 然后: 你 ...
- react的this.setState详细介绍
this.setState是react类组件中最常用的一个react API,使用它可以改变state从而改变页面.今天我们就来详细的学习一下这个东西.比如: import React, { Comp ...
- 160-PHP 文本替换函数str_replace(一)
<?php $str='Hello world!'; //定义源字符串 $search='o'; //定义将被替换的字符 $replace='O'; //定义替换的字符串 $res=str_re ...
- 《新标准C++程序设计》3.1.4-3.2(C++学习笔记6)
1.类型转换构造函数 (1)定义 只有一个参数,而且不是复制构造函数的构造函数,一般就可以看作是转换构造函数. 当需要的时候,编译系统会自动调用转换构造函数,建立一个无名的临时对象(或临时变量). ( ...
- python+opencv+dlib瘦脸效果
对实现人脸瘦脸简单功能的一个记录,大概流程如下: 1.使用dlib检测出人脸关键点 2.使用Interactive Image Warping 局部平移算法实现瘦脸 参考:https://blog.c ...
- Linux每日一练20200219
- PHP基础(9.27 第十三天)
什么是PHP,为什么要学习PHP: (1)php是嵌入html页面中的脚本语言 (2)目前最流行的网站开发语言 (3)在几乎所有平台中都可以运行 (4)很多企业都在使用PHP作为开发语言 P ...
- P 1023 组个最小数
转跳点:
- 使用IDEA打对应结构的Jar包
发布环境的内容和自己项目默认打包的样式不一样,就需要自定义打印jar包内容. 1.打开右上角项目结构 2.进行图片相关设置 3.直接进行打包,包会出现在class文件里面.解压软件解压开就是自己想要的 ...
