43道多线程面试题,附带答案(三)

1.volatile关键字在Java中有什么做用?

volatile是一个特殊的修饰符,只有成员变量才能使用它。java

在Java并发程序缺乏同步类的状况下,多线程对成员变量的操做对其它线程是透明的。安全

volatile变量能够保证下一个读取操做会在前一个写操做以后发生。多线程

2.volatile 变量和 atomic 变量有什么不一样?

首先,volatile 变量和 atomic 变量看起来很像,但功能却不同。架构

Volatile变量能够确保先行关系,即写操做会发生在后续的读操做以前, 但它并不能保证原子性。例如用volatile修饰count变量那么 count++ 操做就不是原子性的。并发

而AtomicInteger类提供的atomic方法可让这种操做具备原子性如getAndIncrement()方法会原子性的进行增量操做把当前值加一,其它数据类型和引用变量也能够进行类似操做。dom

3.Java中的同步集合与并发集合有什么区别?

同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。异步

Java5介绍了并发集合像ConcurrentHashMap,不只提供线程安全还用锁分离和内部分区等现代技术提升了可扩展性。分布式

4.Vector是一个线程安全类吗?

Vector 是用同步方法来实现线程安全的函数

5.ReadWriteLock是什么?

通常而言,读写锁是用来提高并发程序性能的锁分离技术的成果。高并发

Java中的ReadWriteLock是Java 5 中新增的一个接口,一个ReadWriteLock维护一对关联的锁,一个用于只读操做一个用于写。在没有写线程的状况下一个读锁可能会同时被多个读线程持有。写锁是独占的,你可使用JDK中的ReentrantReadWriteLock来实现这个规则,它最多支持65535个写锁和65535个读锁。

6.什么是FutureTask?

在Java并发程序中FutureTask表示一个能够取消的异步运算。

它有启动和取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回,若是运算还没有完成get方法将会阻塞。一个FutureTask对象能够对调用了Callable和Runnable的对象进行包装,因为FutureTask也是调用了Runnable接口因此它能够提交给Executor来执行。

7.什么是ThreadLocal变量?

ThreadLocal是Java里一种特殊的变量。

每一个线程都有一个ThreadLocal就是每一个线程都拥有了本身独立的一个变量,竞争条件被完全消除了。它是为建立代价高昂的对象获取线程安全的好方法,好比你能够用ThreadLocal让SimpleDateFormat变成线程安全的,由于那个类建立代价高昂且每次调用都须要建立不一样的实例因此不值得在局部范围使用它,若是为每一个线程提供一个本身独有的变量拷贝,将大大提升效率。

首先,经过复用减小了代价高昂的对象的建立个数。 其次,你在没有使用高代价的同步或者不变性的状况下得到了线程安全。

线程局部变量的另外一个不错的例子是ThreadLocalRandom类,它在多线程环境中减小了建立代价高昂的Random对象的个数。

8.什么是Java线程转储(Thread Dump),如何获得它?

线程转储是一个JVM活动线程的列表,它对于分析系统瓶颈和死锁很是有用。

有不少方法能够获取线程转储——使用Profiler,Kill-3命令,jstack工具等等。有的更喜欢jstack工具,由于它容易使用而且是JDK自带的。因为它是一个基于终端的工具,因此能够编写一些脚本去定时的产生线程转储以待分析。

9.若是你提交任务时,线程池队列已满。会时发会生什么?

若是你使用的LinkedBlockingQueue,也就是无界队列的话,不要紧,继续添加任务到阻塞队列中等待执行,由于LinkedBlockingQueue能够近乎认为是一个无穷大的队列,能够无限存听任务;

若是你使用的是有界队列比方说ArrayBlockingQueue的话,任务首先会被添加到ArrayBlockingQueue中,ArrayBlockingQueue满了,则会使用拒绝策略RejectedExecutionHandler处理满了的任务,默认是AbortPolicy。

10.线程之间是如何通讯的?

当线程间是能够共享资源时,线程间通讯是协调它们的重要的手段。

Object类中wait()notify()notifyAll()方法能够用于线程间通讯关于资源的锁的状态。

11.怎么检测一个线程是否持有对象监视器

Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候,才会返回true.注意这是一个static方法,这意味着”某条线程”指的是当前线程。

12.什么是死锁(Deadlock)?

死锁是指两个或两个以上的进程在执行过程当中,因争夺资源而形成的一种互相等待的现象,若无外力做用,它们都将没法推动下去。

锁的分类

一、自旋锁 二、自旋锁的其余种类 三、阻塞锁 四、可重入锁 五、读写锁 六、互斥锁 七、悲观锁 八、乐观锁 九、公平锁 十、非公平锁 十一、偏向锁 十二、对象锁 1三、线程锁 1四、锁粗化 1五、轻量级锁 1六、锁消除 1七、锁膨胀 1八、信号量

死锁发生的几个条件是什么

  • 由于系统资源不足。
  • 进程运行推动的顺序不合适。
  • 资源分配不当。

实现一个死锁?

产生死锁的四个必要条件:

  • 互斥条件:所谓互斥就是进程在某一时间内独占资源。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已得到的资源保持不放。
  • 不剥夺条件:进程已得到资源,在末使用完以前,不能强行剥夺。
  • 循环等待条件:若干进程之间造成一种头尾相接的循环等待资源关系。

13.如何避免死锁?

打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。

  1. 打破互斥条件。即容许进程同时访问某些资源。可是,有的资源是不容许被同时访问的,像打印机等等,这是由资源自己的属性所决定的。因此,这种办法并没有实用价值。
  2. 打破不可抢占条件。即容许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能当即被知足时,它必须释放所占有的所有资源,之后再从新申请。它所释放的资源能够分配给其它进程。这就至关于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会下降系统性能。
  3. 打破占有且申请条件。能够实行资源预先分配策略。即进程在运行前一次性地向系统申请它所须要的所有资源。若是某个进程所需的所有资源得不到知足,则不分配任何资源,此进程暂不运行。只有当系统可以知足当前进程的所有资源需求时,才一次性地将所申请的资源所有分配给该进程。因为运行的进程已占有了它所需的所有资源,因此不会发生占有资源又申请资源的现象,所以不会发生死锁。 四.打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会造成环路。全部进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。

14.Java中活锁和死锁有什么区别?

活锁和死锁相似,不一样之处在于处于活锁的线程或进程的状态是不断改变的,活锁能够认为是一种特殊的饥饿。

一个现实的活锁例子是两我的在狭小的走廊碰到,两我的都试着避让对方好让彼此经过,可是由于避让的方向都同样致使最后谁都不能经过走廊。

简单的说就是,活锁和死锁的主要区别是前者进程的状态能够改变可是却不能继续执行。

15.死锁与饥饿的区别?

饥饿是指系统不能保证某个进程的等待时间上界,从而使该进程长时间等待,当等待时间给进程推动和响应带来明显影响时,称发生了进程饥饿。当饥饿到必定程度的进程所赋予的任务即便完成也再也不具备实际意义时称该进程被饿死。

死锁是指在多道程序系统中,一组进程中的每个进程都无限期等待被该组进程中的另外一个进程所占有且永远不会释放的资源。

相同点:两者都是因为竞争资源而引发的。

不一样点:

  • 从进程状态考虑,死锁进程都处于等待状态,忙等待(处于运行或就绪状态)的进程并不是处于等待状态,但却可能被饿死;
  • 死锁进程等待永远不会被释放的资源,饿死进程等待会被释放但却不会分配给本身的资源,表现为等待时限没有上界(排队等待或忙式等待);
  • 死锁必定发生了循环等待,而饿死则否则。这也代表经过资源分配图能够检测死锁存在与否,但却不能检测是否有进程饿死;
  • 死锁必定涉及多个进程,而饥饿或被饿死的进程可能只有一个。
  • 在饥饿的情形下,系统中有至少一个进程能正常运行,只是饥饿进程得不到执行机会。而死锁则可能会最终使整个系统陷入死锁并崩溃。

16.什么是乐观锁和悲观锁

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操做。 乐观锁:假设不会发生并发冲突,只在提交操做时检查是否违反数据完整性。乐观锁不能解决脏读的问题。

17.什么是对象锁?

对象锁是指Java为临界区synchronized(Object)语句指定的对象进行加锁,对象锁是独占排他锁。

对于对象锁,是针对一个对象的,它只在该对象的某个内存位置声明一个标志位标识该对象是否拥有锁,因此它只会锁住当前的对象。通常一个对象锁是对一个非静态成员变量进行syncronized修饰,或者对一个非静态方法进行syncronized修饰。对于对象锁,不一样对象访问同一个被syncronized修饰的方法的时候不会阻塞住。

18.怎么检测一个线程是否拥有锁?

在java.lang.Thread中有一个方法叫holdsLock(),它返回true若是当且仅当当前线程拥有某个具体对象的锁。

19.Java中synchronized 和 ReentrantLock 有什么不一样?

Java在过去很长一段时间只能经过synchronized关键字来实现互斥,它有一些缺点。好比你不能扩展锁以外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 经过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义且它还具备可扩展性。

20.可重入锁的含义

可重入锁,也叫作递归锁,指的是同一线程 外层函数得到锁以后 ,内层递归函数仍然有获取该锁的代码,但不受影响。

在Java环境下 ReentrantLock 和synchronized 都是可重入锁

21.什么是CAS

CAS,全称为Compare and Swap,即比较-替换。假设有三个操做数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才会将内存值修改成B并返回true,不然什么都不作并返回false。固然CAS必定要volatile变量配合,这样才能保证每次拿到的变量是主内存中最新的那个值,不然旧的预期值A对某条线程来讲,永远是一个不会变的值A,只要某次CAS操做失败,永远都不可能成功

 

原文:Java架构笔记

免费Java高级资料须要本身领取,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G。     
传送门:      https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q
相关文章
相关标签/搜索