JAVA那点破事!并发、IO模型、集合、线程池、死锁、非阻塞、AQS....
关于Java面试,面试官一般喜欢问哪些问题?
本文对一些高频问题做了汇总,为了便于大家查找问题,了解全貌,整理个目录,我们可以快速全局了解关于 JAVA
接下来,我们逐条来看看每个问题及答案
JDK、JRE、JVM 三者有什么关系?
答案:
JDK(全称 Java Development Kit),Java开发工具包,能独立创建、编译、运行程序。
JDK = JRE + java开发工具(javac.exe/java.exe/jar.exe)
JRE(全称 Java Runtime Environment),能运行已编译好的程序,但不能创建程序
JRE = JVM + java核心类库
JVM (全称 Java Virtual Machine),java虚拟机。
java创建对象有哪些方式?
答案:
1、new 创建对象
2、反射机制创建对象
3、通过clone方法
4、序列化机制
== 和 equals 有什么区别?
答案:
== ,如果是基本数据类型,比较两个值是否相等;如果是对象,比较两个对象的引用是否相等,指向同一块内存区域
equals,用于对象之间,比较两个对象的值是否相等。
hashCode()的作用?
答案:生成哈希码,int类型,用于确定该对象在哈希表中的索引位置。每个类中都包含这个方法。
String、StringBuffer、StringBuilder 有什么区别?
答案
1、String。采用
final
修饰,对象不可变,线程安全。如果对一个已经存在的String对象修改,会重新创建一个新对象,并把值放进去。2、StringBuffer,采用
synchronized
关键字修饰,线程安全3、StringBuilder,非线程安全,但效率会更高些,适用于单线程。
try-catch-finally,如catch中return了,还会执行finally吗?
答案:当然啦,会在return之前执行。
进程和线程的区别?
答案:
进程:是一个程序的执行流程,是系统进行资源分配和调度的基本单位,作用是程序能够并发执行提高资源利用率。因为进程的创建、销毁、切换产生大量的时间和空间的开销,所以进程的数量不能太多
线程:是比进程更小的能独立运行的基本单位,他是进程的一个实体,可以减少程序并发执行时的时间和空间开销,使得操作系统具有更好的并发性。多个线程可以共享进程的系统资源。线程基本不拥有系统资源,只有一些运行时必不可少的资源,比如程序计数器、寄存器和栈,进程则占有堆。
synchronized 的内部原理?
答案:java提供的原子性内置锁,也被称为监视器锁。使用synchronized
之后,会在编译之后在同步的代码块前后加上monitorenter
和monitorexit
字节码指令,依赖操作系统底层互斥锁实现。实现原子性操作和解决共享变量的内存可⻅性问题。
内部处理过程(内部有两个队列waitSet和entryList。):
1、当多个线程进入同步代码块时,首先进入
entryList
2、有一个线程获取到monitor锁后,就赋值给当前线程,并且计数器+1
3、如果线程调用wait方法,将释放锁,当前线程置为null,计数器-1,同时进入
waitSet
等待被唤醒,调用notify或者notifyAll之后又会进入entryList竞争锁4、如果线程执行完毕,同样释放锁,计数器-1,当前线程置为null
synchronized 和 ReentrantLock 的区别?
答案:
ReentrantLock 实现了Lock接口。synchronized是系统关键字
ReentrantLock需要手动指定锁范围。synchronized 支持同步块、同步方法
都具有可重入性
默认都是非公平锁。但 ReentrantLock 还支持公平模式,但性能会急剧下降
ReentrantLock 需要显示的获取锁、释放锁
ReentrantLock 支持多种方式获取锁。
lock():阻塞模式来获取锁
lockInterruptibly:阻塞式获取锁,支持中断
tryLock():非阻塞模式尝试获取锁
tryLock(long timeout, TimeUnit unit):同上,支持时间设置
ReentrantLock 可以同时绑定多个Condition条件对象。
AQS (AbstractQueuedSynchronizer 抽象队列同步器 )的原理?
答案:AQS内部维护一个state状态位
,尝试加锁的时候通过CAS(CompareAndSwap)
修改值,如果成功设置为 1,并且把当前线程ID赋值,则代表加锁成功。
一旦获取到锁,其他的线程将会被阻塞进入阻塞队列自旋,获得锁的线程释放锁的时候将会唤醒阻塞队列中的线程,释放锁的时候则会把state
重新置为0,同时当前线程ID
置为空。
CAS 有什么缺点?
答案:在多线程场景下,更新变量值被其他线程跑了个对冲,CAS会出现ABA问题。解决方式有很多,
可以通过,自增版本号方式,永远不会回退
Java中提供了
AtomicStampedReference
,增加了标志字段,更新时不光检查值,还要检查当前的标志是否等于预期标志,全部满足条件才会更新更多内容,CAS原理分析,解决银行转账ABA难题
Java 都用过哪些锁?
答案:
乐观锁、悲观锁
分布式锁
独占锁、共享锁
互斥锁
读写锁
公平锁、非公平锁
可重入锁
自旋锁
分段锁
锁升级(无锁|偏向锁|轻量级锁|重量级锁)
锁优化技术(锁粗化、锁消除)
更多详细内容,一文全面梳理各种锁机制
HashMap原理?
答案:内部由数组和链表组成,非线程安全。JDK1.7和1.8的主要区别在于头插和尾插方式的修改,头插容易导致HashMap链表死循环,并且1.8之后加入红黑树
对性能有提升。
put插入:key 计算hash值,取模,找到数组位置,如果数组中没有元素直接存入,反之,则判断key是否相同,key相同就覆盖,否则就会插入到链表的尾部。如果链表的⻓度超过8且数据总量超过64,则会转换成
红黑树
。最后判断元素个数是否超过默认的⻓度(16)*负载因子(0.75),也就是12,超过则进行扩容。get查询:计算出hash值,然后去数组查询,是红黑树就去红黑树查,链表就遍历链表查询就可以了。
红黑树的时间复杂度 O(logn);链表的时间复杂度 O(n),当链表过长时,红黑树能大大提高查询性能。
ConcurrentHashMap 如何能保证线程安全的?
答案:ConcurrentHashmap在JDK1.7和1.8的版本改动比较大。
1.7 使用Segment + HashEntry 分段锁的方式实现,
Segment
继承于ReentrantLock
,HashEntry
存储键值对数据。1.8 采用数组+ 链表 + 红黑树。锁设计上抛弃了Segment分段锁,采用 CAS + synchronized 实现。
ArrayList 和 LinkedList 有什么区别?
答案:
1、Arraylist
非线程安全
底层采用数组存储
插入、删除元素,时间复杂度受位置影响。默认是添加在列表的末尾,如果在位置 k 插入或删除一个元素,需要将k后面的元素后移或前移一位。
支持随机访问,根据索引下标序号,可以快速定位元素
需要连续的内存空间,中间不能有碎片
2、LinkedList
非线程安全
底层采用双向循环链表存储
插入、删除元素,时间复杂度不受位置影响,只需要更改位置 k的前后指针地址,时间复杂度为 O(1)
不支持高效的随机访问
不需要连续的内存空间
volatile 原理?
答案:volatile声明的变量,值被更新后对其他线程立即可⻅。
CPU会根据缓存一致性协议,强制线程重新从主内存加载最新的值到自己的工作内存中,而不是直接用cpu缓存中的值。
ThreadLocal 原理?
答案:ThreadLocal有一个静态内部类ThreadLocalMap
,ThreadLocalMap
又包含了一个Entry数组,Entry本身是一个弱引用,他的key是指向ThreadLocal的弱引用,Entry具备保存key -- value键值对的能力。
在使用完之后调用remove方法
删除Entry对象,避免出现内存泄露。
什么是工作内存、主内存?
答案:
工作内存:寄存器、CPU缓存(L1、L2、L3)
主内存:主要是指物理内存
JUC并发包用过哪些线程安全的类?
答案:
ConcurrentHashMap
CountDownLatch、CyclicBarrier
Semaphore
BlockingQueue
ThreadPoolExecutor
ReentrantLock、ReentrantReadWriteLock
CompletableFuture
ThreadPoolExecutor 有哪些构造参数?
答案:核心线程数、最大线程数、最大空闲时间、时间单位、任务队列、线程工厂、拒绝策略
更多内容,参考 史上最全ThreadPoolExecutor梳理(上篇)
更多内容,参考 史上最全ThreadPoolExecutor梳理(下篇)
ThreadPoolExecutor 的拒绝策略有哪些?
答案:
1、AbortPolicy:直接丢弃任务,抛出异常,这是默认策略
2、CallerRunsPolicy:只用调用者所在的线程来处理任务
3、DiscardOldestPolicy:丢弃等待队列中最旧的任务,并执行当前任务
4、DiscardPolicy:直接丢弃任务,也不抛出异常
5、使用
RejectedExecutionHandler
接口,自定义实现
线程有哪些状态?是如何转换?
答案:New、Runnable、Running、Blocked、Waiting、Timed Waiting、Terminated
IO 模型有哪五种?
答案:
1、阻塞IO。当 应用B 发起读取数据申请时,如果内核数据没有准备好,应用B会一直处于等待数据状态,直到内核把数据准备好了交给应用B才结束。
2、非阻塞IO。当应用B发起读取数据申请时,如果内核数据没有准备好会即刻告诉应用B,不会让B在这里等待。
3、IO复用模型。进程通过将一个或多个fd传递给select,阻塞在select操作上,select帮我们侦测多个fd是否准备就绪,当有fd准备就绪时,select返回数据可读状态,应用程序再调用recvfrom读取数据。
4、信号IO。信号驱动IO不是用循环请求询问的方式去监控数据就绪状态,而是在调用sigaction时候建立一个SIGIO的信号联系,当内核数据准备好之后再通过SIGIO信号通知线程数据准备好后的可读状态,当线程收到可读状态的信号后,此时再向内核发起recvfrom读取数据的请求,因为信号驱动IO的模型下应用线程在发出信号监控后即可返回,不会阻塞,所以这样的方式下,一个应用线程也可以同时监控多个fd。
5、异步IO。解决了应用程序需要先后查看数据是否就绪
、发送接收数据请求
两个阶段的模式,在异步IO的模式下,只需要向内核发送一次请求就可以完成状态查询和数据拷贝的所有操作。
阻塞IO 和 非阻塞IO 的区别?
答案:如果数据没有就绪,在查看数据是否就绪
的这个阶段是一直等待?还是直接返回一个标志信息。
JAVA那点破事!并发、IO模型、集合、线程池、死锁、非阻塞、AQS....相关推荐
- 多线程与高并发 笔记,非面向初学者 二:java引用,高并发多线程容器,线程池
网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容 如果右边没有就找找左边 上一节:JUC锁,一些面试题和源码讲解 1.引用 java引用共4种,强软弱虚 强引用:我们普通的new一个对象,就 ...
- 【Java进阶】Java并发类库提供的线程池有哪几种? 分别有什么特点?
我在专栏第 17 讲中介绍过线程是不能够重复启动的,创建或销毁线程存在一定的开销,所以利用线程池技术来提高系统资源利用效率,并简化线程管理,已经是非常成熟的选择. 今天我要问你的问题是,Java 并发 ...
- Java并发(五)线程池使用番外-分析RejectedExecutionException异常
Java并发(五)线程池使用番外-分析RejectedExecutionException异常 参考文章: (1)Java并发(五)线程池使用番外-分析RejectedExecutionExcepti ...
- 并发编程之 Executor 线程池原理与源码解读
并发编程之 Executor 线程池原理与源码解读 线程是调度 CPU 资源的最小单位,线程模型分为 KLT 模型与 ULT 模型,JVM使用的是 KLT 模型.java线程与 OS 线程保持 1:1 ...
- 并发编程之Executor线程池原理与源码解读
1. 线程池 "线程池",顾名思义就是一个线程缓存,线程是稀缺资源,如果被无限制的创建,不 仅会消耗系统资源,还会降低系统的稳定性,因此Java中提供线程池对线程进行统一分配. 调 ...
- Java多线程学习总结(7)——创建线程池的正确姿势
一. 通过Executors创建线程池的弊端 在创建线程池的时候,大部分人还是会选择使用Executors去创建. 下面是创建定长线程池(FixedThreadPool)的一个例子,严格来说,当使用如 ...
- 后端开发【一大波有用知识】Redis中的IO多线程(线程池)
一.Redis中的IO多线程原理 服务端收到一条信息,给它deconde成一条命令 然后根据命令获得一个结果(reply) 然后将结果encode后,发送回去 redis的单线程是指,命令执行(lo ...
- JAVA那点破事,并发、IO模型、集合、线程池、死锁、非阻塞、AQS...
JDK.JRE.JVM 三者有什么关系? 答案: JDK(全称 Java Development Kit),Java开发工具包,能独立创建.编译.运行程序. JDK = JRE + java开发工具( ...
- 《Java并发编程的艺术》——Java中的并发工具类、线程池、Execute框架(笔记)
文章目录 八.Java中的并发工具类 8.1 等待多线程完成的CountDownLatch 8.2 同步屏障CyclicBarrier 8.2.1 CyclicBarrier简介 8.2.2 Cycl ...
最新文章
- POJ2533解题报告
- 循环查询sql带逗号(,)分隔的数据 以及一对多数据转化为逗号(,)分割数据...
- 软件公司各种角色透视图
- 计算机应用基础案例实训教程,计算机应用基础案例式实训教程
- C、C++和C#区别概述
- tshark mysql_使用tshark抓包分析http请求
- ASP.NET Core——身份验证UI安装
- foreach循环符合就不往下走了_游泳池循环方式及循环周期
- Photoshop二次开发接口介绍
- 游戏策划学习:笔试整理
- GitHub下载提速
- LT7911D功能概述 LT7911D是Type-C/DP1.2转双路MIPI/Lvds的一款芯片
- 大学生创新创业项目管理系统
- position四个属性详解
- MYSQL数据库--存储引擎
- java解析网页全过程_Web页面的解析过程
- 《隐秘的角落》里笛卡尔的爱情故事,是真的吗?
- 使用FME实现PGDB转CAD并赋eed属性
- 百特搭入选《2021中国低代码/零代码全景产业研究报告》
- 医师android,医师服务APP
热门文章
- mvn 默认scope_maven scope 的作用
- vue引用js文件的多种方式
- ASP.NET Web Pages – 页面布局简介
- java怎么打开_java开不了怎么办?java怎么打开?
- 是什么轮胎_为什么现在的车轮胎轮毂尺寸越来越大
- 习题4-3 求分数序列前N项和 (15 分)
- 矩阵消除游戏--牛客练习赛58
- 开发缺点_成都嗨创科技:原生APP开发与混合APP开发的优缺点对比
- ubuntu mysql 改密码_tpcc-mysql 压力测试
- D - Sand Fortress CodeForces - 985D