1 Star 0 Fork 31

阿明 / Ebooks

forked from Java精选 / Ebooks 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
2022年最全Java并发面试题附答案解析大汇总.md 10.27 KB
一键复制 编辑 原始数据 按行查看 历史

2022年最全Java并发面试题附答案解析大汇总

全部面试题答案,更新日期:01月30日,直接下载吧!

下载链接:高清500+份面试题资料及电子书,累计 10000+ 页大厂面试题 PDF

Java 并发

题1:Java 中如何实现多线程之间的通讯和协作?

中断和共享变量。

题2:Java 线程池中 submit() 和 execute() 方法有什么区别?

submit()和execute()两个方法都可以向线程池提交任务。

execute()方法的返回类型是void,它定义在Executor接口中。

submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。

题3:如何解决 ABA 问题?

ABA问题:如果线程1第一次读取的值为A,线程1准备对A执行写操作,但这段时间,线程2完成了A->B->A的更改,当线程1准备写时,A已经不是原来的A。

JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。

如何解决ABA问题?

JDK1.5版本后,推出两种办法解决或改善ABA问题,分别是AtomicStampedRefence和AtomicMarkableReference。

1、AtomicStampedRefence

观察其源码发现:其内部的value被pair代替,即:

private volatile Pair<V> pair;

pair源码:

private static class Pair<T> {
    final T reference;
    final int stamp;
    private Pair(T reference, int stamp) {
        this.reference = reference;
        this.stamp = stamp;
    }
    static <T> Pair<T> of(T reference, int stamp) {
        return new Pair<T>(reference, stamp);
    }
}

可以看到其内部不仅有T引用模板,还有一个int类型的stamp作为版本号,等修改时比较当前版本号与当前线程持有的版本号是否一致,若一直则修改,并stamp+1。

2、AtomicMarkableReference

观察其源码发现:其内部的value被pair代替,即:

private volatile AtomicMarkableReference.Pair<V> pair;

pair源码:

static <T> AtomicMarkableReference.Pair<T> of(T var0, boolean var1) {
    return new AtomicMarkableReference.Pair(var0, var1);
}

可以看到其内部不仅有T引用模板,还有一个boolean类型的var1。

var1的值有两个true和false,修改时在这两个版本号之间来回切换,这样做并不能解决ABA问题,但可以降低其发生的几率。

解决的办法

加个版本号就可以解决ABA问题。真正要做到严谨的CAS机制,在Compare阶段不仅要比较期望值A和地址V中的实际值,还要比较变量的版本号是否一致。

用例子来说明一下,假设地址V中存储着变量值A,当前版本号是01。

线程1获得了当前值A和版本号01,想要更新为B,但是被阻塞了。

此时内存地址V中的变量发生了多次改变,版本号提升为03,但是变量值仍然是A。

随后线程1恢复运行,进行Compare操作。经过比较,线程1所获得的值和地址V的实际值都是A,但是版本号不相等,所以这一次更新失败。在Java当中AtomicStampedReference类就实现了用版本号做比较的CAS机制。

题4:ConcurrentHashMap 和 Hashtable 有什么区别?

ConcurrentHashMap和Hashtable都可以用于多线程的环境,但当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。

HashTable的任何操作都会把整个表锁住,是阻塞的。好处是:总能获取最实时的更新,比如说线程A调用putAll()写入大量数据,期间线程B调用get(),线程B就会被阻塞,直到线程A完成putAll(),因此线程B肯定能获取到线程A写入的完整数据。坏处是所有调用都需要排队,效率较低。

ConcurrentHashMap是设计为非阻塞的。在更新时会局部锁住某部分数据,但不会把整个表都锁住。同步读取操作则是完全非阻塞的。好处是在保证合理的同步前提下,效率很高。坏处是:严格来说,读取操作不能保证反映最近的更新。例如线程A调用putAll()写入大量数据,期间线程B调用get(),则只能get()到目前为止已经顺利插入的部分数据。

JDK8的版本,与JDK6的版本有很大差异。实现线程安全的思想也已经完全变了,它摒弃了Segment(分段锁)的概念,而是启用了一种全新的方式实现,利用CAS算法。它沿用了与它同时期的HashMap版本的思想,底层依然由数组+链表+红黑树的方式思想,但是为了做到并发,又增加了很多复制类,例如TreeBin、Traverser等对象内部类。CAS算法实现无锁化的修改至操作,他可以大大降低锁代理的性能消耗。这个算法的基本思想就是不断地去比较当前内存中的变量值与你指定的一个变量值是否相等,如果相等,则接受你指定的修改的值,否则拒绝你的操作。因为当前线程中的值已经不是最新的值,你的修改很可能会覆盖掉其他线程修改的结果。

题5:超出 LinkedBlockingQueue 容量值会出现什么情况?

如果限定LinkedBlockingQueue的容量,当达到容量值的时候put操作和offer操作加上超时时间会阻塞。

如果没有限定容量的话,就可认为容量是无限大,直到耗尽机器的资源,发生OOM。

所以建议在使用LinkedBlockingQueue的时候最好能够设置容量,防止耗尽内容。

题6:使用多线程可能带来什么问题?

并发编程的目的就是为了能提高程序的执行效率提高程序运行速度,但是并发编程并不总是能提高程序运行速度的,而且并发编程可能会遇到很多问题。

比如:内存泄漏、上下文切换、死锁还有受限于硬件和软件的资源闲置问题。

题7:什么是FutureTask?

Java并发程序中FutureTask表示一个可以取消的异步运算。

FutureTask有启动和取消运算、查询运算是否完成和取回运算结果等方法。

只有当运算完成的时候结果才能取回,如果运算尚未完成get方法将会阻塞。

一个FutureTask对象可以对调用了Callable和Runnable的对象进行包装,由于FutureTask也是调用了Runnable接口所以它可以提交给Executor来执行。

题8:Java 中 AQS 实现方式是什么?

AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态。

题9:线程池都有哪些拒绝策略?

当线程池的任务缓存队列已满且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务

ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务。

题10:Java 中 interrupted 和 isInterrupted 方法有什么区别?

interrupt

interrupt方法用于中断线程。调用该方法的线程的状态为将被置为”中断”状态。

注意:线程中断仅仅是置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态为并做处理。支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。

interrupted

查询当前线程的中断状态,并且清除原状态。如果一个线程被中断了,第一次调用interrupted则返回true,第二次和后面的就返回false了。

isInterrupted

仅仅是查询当前线程的中断状态。

题11:如何检测一个线程是否拥有锁

题12:java-中-semaphore-是什么

题13:程序计数器为什么是私有的

题14:java-中如何唤醒一个阻塞的线程

题15:如何保证两个线程间共享数据

题16:线程运行时发生异常会造成什么问题

题17:什么是竞争条件如何发现和解决竞争

题18:java-支持协程吗

题19:cas-有什么缺点

题20:java-中-concurrenthashmap-并发度是什么

题21:线程池的原理是什么

题22:copyonwritearraylist-可以用于什么应用场景

题23:thread-类中-start()-和-run()-方法有什么区别

题24:java-中-aqs-核心思想是什么

题25:什么是进程

大厂面试题

大厂面试题

大厂面试题

Java
1
https://gitee.com/AminDev/ebooks.git
git@gitee.com:AminDev/ebooks.git
AminDev
ebooks
Ebooks
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891