并发编程可以说是Java程序员必须掌握的技能之一,也是最难掌握的一种技能。它要求编程者对计算机最底层的运作原理有深刻的理解,同时要求编程者逻辑清晰、思维缜密,这样才能写出高效、安全、可靠的多线程并发程序。
所以很多大厂面试经常会问到关于Java并发编程的问题来考验面试者的水平。那么面试者到底该如何应对呢?
这里我通过阿里,京东,字节跳动等大厂的是面试题总结了25道并发编程必问的难题,先把问题列举出来,后面将进行分析以及解答。
synchronized 关键字
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
1. 说一说自己对于 synchronized 关键字的了解
2. 说说自己是怎么使用 synchronized 关键字,在项目中用到了吗
3. 讲一下 synchronized 关键字的底层原理
4. 说说 JDK1.6 之后的synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗
5. 谈谈 synchronized和ReentrantLock 的区别
volatile关键字
volatile作为java中的关键词之一,用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值)。volatile会禁止指令重排。
6. 讲一下Java内存模型
7. 说说 synchronized 关键字和 volatile 关键字的区别
ThreadLocal
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。
在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。
8. ThreadLocal简介
9. ThreadLocal示例
10. ThreadLocal原理
11. ThreadLocal 内存泄露问题
线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
12. 为什么要用线程池?
13. 实现Runnable接口和Callable接口的区别
14. 执行execute()方法和submit()方法的区别是什么呢?
15. 如何创建线程池
16. ThreadPoolExecutor 类分析
17. 一个简单的线程池Demo:Runnable+ThreadPoolExecutor
18. 线程池原理分析
Atomic 原子类
在并发编程中很容易出现并发安全的问题,有一个很简单的例子就是多线程更新变量i=1,比如多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchronized进行控制来达到线程安全的目的。但是由于synchronized是采用的是悲观锁策略,并不是特别高效的一种解决方案。
实际上,在J.U.C下的atomic包提供了一系列的操作简单,性能高效,并能保证线程安全的类去更新基本类型变量,数组元素,引用类型以及更新对象中的字段类型。atomic包下的这些类都是采用的是乐观锁策略去原子更新数据,在java中则是使用CAS操作具体实现。
19.介绍一下Atomic 原子类
20. JUC 包中的原子类是哪4类?
21. 讲讲 AtomicInteger 的使用
22. 能不能给我简单介绍一下 AtomicInteger 类的原理
AQS
AQS是AbstractQueuedSynchronizer的简称。AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架,
如下图所示。AQS为一系列同步器依赖于一个单独的原子变量(state)的同步器提供了一个非常有用的基础。子类们必须定义改变state变量的protected方法,这些方法定义了state是如何被获取或释放的。鉴于此,本类中的其他方法执行所有的排队和阻塞机制。子类也可以维护其他的state变量,但是为了保证同步,必须原子地操作这些变量。
23. AQS 介绍
24. AQS 原理分析
25. AQS 组件总结
面试题答案
好了,Java并发编程中的面试难题一共就这么多,只要解决这些难题,剩下也就就都迎刃而解了。
面试题领取方式:关注宫众浩【java开发之路】回复【资料】即可获得完整版面试题答案。