Java面试集锦:25道线程类相关面试题与答案(二)

Java面试集锦:25道线程类相关面试题与答案(二) .png

Java面试集锦:25道线程类相关面试题与答案(一)java

26. 并发编程三要素?

1)原子性 原子性指的是一个或者多个操做,要么所有执行而且在执行的过程当中不被其余操做打断,要么就所有都不执行。git

2)可见性 可见性指多个线程操做一个共享变量时,其中一个线程对变量进行修改后,其余线程能够当即看到修改的结果。github

3)有序性 有序性,即程序的执行顺序按照代码的前后顺序来执行。面试

27. Thread.sleep(0)的做用是什么?

因为Java采用抢占式的线程调度算法,所以可能会出现某条线程经常获取到CPU控制权的状况,为了让某些优先级比较低的线程也能获取到CPU控制权,可使用Thread.sleep(0)手动触发一次操做系统分配时间片的操做,这也是平衡CPU控制权的一种操做。算法

28. java中的++操做符线程安全么??

不是线程安全的操做。它涉及到多个指令,如读取变量值,增长,而后存储回内存,这个过程可能会出现多个线程交差编程

29. Runnable和Callable有什么区别?

Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run()。 Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 Call方法能够抛出异常,run方法不能够。 运行Callable任务能够拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。经过Future对象能够了解任务执行状况,可取消任务的执行,还可获取执行结果。安全

30. 介绍一下线程中的五种基本状态:

1)新建状态(New):当线程对象对建立后,即进入了新建状态,如:Thread t = new MyThread();微信

2)就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经作好了准备,随时等待CPU调度执行,并非说执行了t.start()此线程当即就会执行;数据结构

3)运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的惟一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;多线程

4)阻塞状态(Blocked):处于运行状态中的线程因为某种缘由,暂时放弃对CPU的使用权,中止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。

根据阻塞产生的缘由不一样,阻塞状态又能够分为三种:

a.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

b.同步阻塞 – 线程在获取synchronized同步锁失败(由于锁被其它线程所占用),它会进入同步阻塞状态;

c.其余阻塞 – 经过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程从新转入就绪状态。

5)死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

31. 线程池的优势?

1)重用存在的线程,减小对象建立销毁的开销。 2)可有效的控制最大并发线程数,提升系统资源的使用率,同时避免过多资源竞争,避免堵塞。 3)提供定时执行、按期执行、单线程、并发数控制等功能。

32. 经常使用的并发工具类有哪些?

CountDownLatch CyclicBarrier Semaphore Exchanger

33. CyclicBarrier和CountDownLatch的区别

1)CountDownLatch简单的说就是一个线程等待,直到他所等待的其余线程都执行完成而且调用countDown()方法发出通知后,当前线程才能够继续执行。 2)cyclicBarrier是全部线程都进行等待,直到全部线程都准备好进入await()方法以后,全部线程同时开始执行! 3)CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可使用reset() 方法重置。因此CyclicBarrier能处理更为复杂的业务场景,好比若是计算发生错误,能够重置计数器,并让线程们从新执行一次。 4)CyclicBarrier还提供其余有用的方法,好比getNumberWaiting方法能够得到CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。若是被中断返回true,不然返回false。

34. synchronized的做用?

在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。 synchronized既能够加在一段代码上,也能够加在方法上。

35. volatile关键字的做用是什么?

对于可见性,Java提供了volatile关键字来保证可见性。 当一个共享变量被volatile修饰时,它会保证修改的值会当即被更新到主存,当有其余线程须要读取时,它会去内存中读取新值。 从实践角度而言,volatile的一个重要做用就是和CAS结合,保证了原子性,详细的能够参见java.util.concurrent.atomic包下的类,好比AtomicInteger。

36.什么是CAS?

CAS是compare and swap的缩写,即咱们所说的比较交换。 cas是一种基于锁的操做,并且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个以前得到锁的线程释放锁以后,下一个线程才能够访问。而乐观锁采起了一种宽泛的态度,经过某种方式不加锁来处理资源,好比经过给记录加version来获取数据,性能较悲观锁有很大的提升。 CAS 操做包含三个操做数 —— 内存位置(V)、预期原值(A)和新值(B)。若是内存地址里面的值和A的值是同样的,那么就将内存里面的值更新成B。CAS是经过无限循环来获取数据的,若果在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程须要自旋,到下次循环才有可能机会执行。 java.util.concurrent.atomic 包下的类大可能是使用CAS操做来实现的( AtomicInteger,AtomicBoolean,AtomicLong)。

37. CAS会出现哪些问题?

1)CAS容易形成ABA问题 一个线程a将数值改为了b,接着又改为了a,此时CAS认为是没有变化,实际上是已经变化过了,而这个问题的解决方案可使用版本号标识,每操做一次version加1。在java5中,已经提供了AtomicStampedReference来解决问题。

2) 不能保证代码块的原子性 CAS机制所保证的知识一个变量的原子性操做,而不能保证整个代码块的原子性。好比须要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。

3)CAS形成CPU利用率增长 以前说过了CAS里面是一个循环判断的过程,若是线程一直没有获取到状态,cpu资源会一直被占用。

38. 什么是Future?

在并发编程中,咱们常常用到非阻塞的模型,在以前的多线程的三种实现中,无论是继承thread类仍是实现runnable接口,都没法保证获取到以前的执行结果。经过实现Callback接口,并用Future能够来接收多线程的执行结果。 Future表示一个可能尚未完成的异步任务的结果,针对这个结果能够添加Callback以便在任务执行成功或失败后做出相应的操做。

39. 什么是AQS?

AQS是AbustactQueuedSynchronizer的简称,它是一个Java提升的底层同步工具类,用一个int类型的变量表示同步状态,并提供了一系列的CAS操做来管理这个同步状态。 AQS是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用普遍的大量的同步器,好比咱们提到的ReentrantLock,Semaphore,其余的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。

40. AQS支持两种同步方式:

1)独占式 2)共享式

这样方便使用者实现不一样类型的同步组件,独占式如ReentrantLock,共享式如Semaphore,CountDownLatch,组合式的如ReentrantReadWriteLock。总之,AQS为使用提供了底层支撑,如何组装实现,使用者能够自由发挥。

41. ReadWriteLock是什么?

首先明确一下,不是说ReentrantLock很差,只是ReentrantLock某些时候有局限。若是使用ReentrantLock,可能自己是为了防止线程A在写数据、线程B在读数据形成的数据不一致,但这样,若是线程C在读数据、线程D也在读数据,读数据是不会改变数据的,没有必要加锁,可是仍是加锁了,下降了程序的性能。 由于这个,才诞生了读写锁ReadWriteLock。ReadWriteLock是一个读写锁接口,ReentrantReadWriteLock是ReadWriteLock接口的一个具体实现,实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提高了读写的性能。

42. FutureTask是什么

这个其实前面有提到过,FutureTask表示一个异步运算的任务。FutureTask里面能够传入一个Callable的具体实现类,能够对这个异步运算的任务的结果进行等待获取、判断是否已经完成、取消任务等操做。固然,因为FutureTask也是Runnable接口的实现类,因此FutureTask也能够放入线程池中。

43. synchronized和ReentrantLock的区别?

synchronized是和if、else、for、while同样的关键字,ReentrantLock是类,这是两者的本质区别。既然ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,能够被继承、能够有方法、能够有各类各样的类变量,ReentrantLock比synchronized的扩展性体如今几点上:

1)ReentrantLock能够对获取锁的等待时间进行设置,这样就避免了死锁 2)ReentrantLock能够获取各类锁的信息 3)ReentrantLock能够灵活地实现多路通知

另外,两者的锁机制其实也是不同的。ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操做的应该是对象头中mark word,这点我不能肯定。

44. synchronized、volatile、CAS比较

synchronized是悲观锁,属于抢占式,会引发其余线程阻塞。 volatile提供多线程共享变量可见性和禁止指令重排序优化。 CAS是基于冲突检测的乐观锁(非阻塞)

45. sleep方法和wait方法有什么区别?

这个问题常问,sleep方法和wait方法均可以用来放弃CPU必定的时间,不一样点在于若是线程持有某个对象的监视器,sleep方法不会放弃这个对象的监视器,wait方法会放弃这个对象的监视器

46. ThreadLocal是什么?有什么用?

ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象作一个映射,各个线程之间的变量互不干扰,在高并发场景下,能够实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操做的场景。

简单说ThreadLocal就是一种以空间换时间的作法,在每一个Thread里面维护了一个以开地址法实现的ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不共享,天然就没有线程安全方面的问题了。

47.一个线程若是出现了运行时异常怎么办?

若是这个异常没有被捕获的话,这个线程就中止执行了。另外重要的一点是:若是这个线程持有某个某个对象的监视器,那么这个对象监视器会被当即释放

48. 线程的调度策略

线程调度器选择优先级最高的线程运行,可是,若是发生如下状况,就会终止线程的运行:

1)线程体中调用了yield方法让出了对cpu的占用权利 2)线程体中调用了sleep方法使线程进入睡眠状态 3)线程因为IO操做受到阻塞 4)另一个更高优先级线程出现 5)在支持时间片的系统中,该线程的时间片用完

49. 怎么唤醒一个阻塞的线程?

若是线程是由于调用了wait()、sleep()或者join()方法而致使的阻塞,能够中断线程,而且经过抛出InterruptedException来唤醒它;若是线程遇到了IO阻塞,无能为力,由于IO是操做系统实现的,Java代码并无办法直接接触到操做系统。

50. 你有哪些多线程开发良好的实践?

  • 给线程命名
  • 最小化同步范围
  • 优先使用volatile
  • 尽量使用更高层次的并发工具而非wait和notify()来实现线程通讯,如BlockingQueue,Semeaphore
  • 优先使用并发容器而非同步容器.
  • 考虑使用线程池

推荐

大厂笔试内容集合(内有详细解析) 持续更新中....

ProcessOn是一个在线做图工具的聚合平台~

文末

欢迎关注我的微信公众号:Coder编程 欢迎关注Coder编程公众号,主要分享数据结构与算法、Java相关知识体系、框架知识及原理、Spring全家桶、微服务项目实战、DevOps实践之路、每日一篇互联网大厂面试或笔试题以及PMP项目管理知识等。更多精彩内容正在路上~ 新建了一个qq群:315211365,欢迎你们进群交流一块儿学习。谢谢了!也能够介绍给身边有须要的朋友。

文章收录至 Github: github.com/CoderMerlin… Gitee: gitee.com/573059382/c… 欢迎关注并star~

微信公众号
相关文章
相关标签/搜索