大厂P7 Java程序员高频面试题-5

Posted 四猿外

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大厂P7 Java程序员高频面试题-5相关的知识,希望对你有一定的参考价值。

什么是可重入锁(ReentrantLock)?

举例来说明锁的可重入性

public class UnReentrant{
Lock lock = new Lock();
public void outer(){
lock.lock();
inner();
lock.unlock();
}
public void inner(){
lock.lock();
//do something
lock.unlock();
}
}

outer 中调用了inner,outer 先锁住了lock,这样inner 就不能再获取lock。其实调用outer 的线程已经获取了lock 锁,但是不能在inner 中重复利用已经获取的锁资源,这种锁即称之为不可重入可重入就意味着:线程可以进入任何一个它已经拥有的锁所同步着的代码块。

synchronized、ReentrantLock 都是可重入的锁, 可重入锁相对来说简化了并发编程的开发。

当一个线程进入某个对象的一个synchronized 的实例方法后,其它线程是否可进入此对象的其它方法?

如果其他方法没有synchronized 的话,其他线程是可以进入的。
所以要开放一个线程安全的对象时, 得保证每个方法都是线程安全的。

SynchronizedMap 和ConcurrentHashMap 有什么区别?

SynchronizedMap 一次锁住整张表来保证线程安全,所以每次只能有一个线程来访为map。
ConcurrentHashMap 使用分段锁来保证在多线程下的性能。

ConcurrentHashMap 中则是一次锁住一个桶。ConcurrentHashMap 默认将hash 表分为16 个桶,诸如get,put,remove 等常用操作只锁当前需要用到的桶。

这样,原来只能一个线程进入,现在却能同时有16 个写线程执行,并发性能的提升是显而易见的。
另外ConcurrentHashMap 使用了一种不同的迭代方式。在这种迭代方式中, 当iterator 被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时new 新的数据从而不影响原有的数据,iterator 完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变。

CopyOnWriteArrayList 可以用于什么应用场景?

CopyOnWriteArrayList(免锁容器)的好处之一是当多个迭代器同时遍历和修改这个列表时,不会抛出ConcurrentModificationException。在CopyOnWriteArrayList 中,写入将导致创建整个底层数组的副本,而源数组将保留在原地,使得复制的数组在被修改时, 读取操作可以安全地执行。

1、由于写操作的时候,需要拷贝数组,会消耗内存,如果原数组的内容比较多的情况下, 可能导致young gc 或者full gc;

2、不能用于实时读的场景,像拷贝数组、新增元素都需要时间,所以调用一个set操作后,读取到数据可能还是旧的,虽然CopyOnWriteArrayList 能做到最终一致性,但是还是没法满足实时性要求;

CopyOnWriteArrayList 透露的思想
1、读写分离,读和写分开
2、最终一致性
3、使用另外开辟空间的思路,来解决并发冲突

什么叫线程安全?servlet 是线程安全吗?

线程安全是编程中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。

Servlet 不是线程安全的,servlet 是单实例多线程的,当多个线程同时访问同一个方法,是不能保证共享变量的线程安全性的。

Struts2 的action 是多实例多线程的,是线程安全的,每个请求过来都会new 一个新的action 分配给这个请求, 请求完成后销毁。

SpringMVC 的Controller 是线程安全的吗? 不是的,和Servlet 类似的处理流程。

Struts2 好处是不用考虑线程安全问题; Servlet 和SpringMVC 需要考虑线程安全问题,但是性能可以提升不用处理太多的gc,可以使用ThreadLocal 来处理多线程的问题。

volatile 有什么用?能否用一句话说明下volatile 的应用场景?

volatile 保证内存可见性和禁止指令重排。
volatile 用于多线程环境下的单次操作(单次读或者单次写)。

为什么代码会重排序?

在执行程序时,为了提供性能,处理器和编译器常常会对指令进行重排序,但是不能随意重排序,不是你想怎么排序就怎么排序, 它需要满足以下两个条件:
在单线程环境下不能改变程序运行的结果;
存在数据依赖关系的不允许重排序

需要注意的是:重排序不会影响单线程环境的执行结果,但是会破坏多线程的执
行语义。

以上是关于大厂P7 Java程序员高频面试题-5的主要内容,如果未能解决你的问题,请参考以下文章

大厂P7 Java程序员高频面试题-7

大厂P7 Java程序员高频面试题-11

大厂P7 Java程序员高频面试题-6

大厂P7 Java程序员高频面试题-9

大厂P7 Java程序员高频面试题-2

大厂P7 Java程序员高频面试题-10