Java多线程面试系列——为什么需要多线程
内容提要
本文介绍了Android开发中关于Java多线程的问题,包括多线程的意图、问题原因和处理方式。讨论了进程和线程的差异,以及为什么需要多线程。还提到了多线程编程中的可见性、原子性和有序性问题,以及如何处理这些问题。最后,介绍了Java内存模型(JMM)和处理可见性、原子性和有序性问题的方法。
延伸解读
多线程在单核CPU下的价值
文章指出,即使只有一个CPU核心,多线程仍然有用。这是因为CPU、内存和IO设备的速度差异巨大,程序性能常受限于IO操作。通过多线程,可以在一个线程等待IO时切换到另一个线程执行,从而提高CPU利用率。因此,单核环境下多线程主要优化的是IO密集型任务,而非计算密集型任务。
可见性、原子性与有序性的根源
文章解释了多线程编程中三个核心问题的来源:可见性问题源于多核CPU的缓存机制,每个核心有自己的缓存,导致线程间变量修改不可见;原子性问题源于非原子操作(如num++)和线程切换;有序性问题源于编译器和处理器的指令重排序。理解这些根源有助于针对性地使用同步机制。
JMM与happens-before原则的作用
Java内存模型(JMM)通过定义主内存与工作内存的抽象,以及八项happens-before原则,来确保并发程序的一致性。这些原则规定了操作之间的可见性和顺序性,如程序次序规则、volatile变量规则等。JMM是跨平台的规范,具体由JVM实现,开发者需遵循这些规则来编写正确的并发代码。
volatile与synchronized的适用场景
文章对比了volatile和synchronized:volatile仅保证可见性和有序性,不保证原子性,且不阻塞线程;synchronized保证原子性、可见性和有序性,但会阻塞线程。因此,volatile适用于状态标志等简单场景,而synchronized适用于需要原子操作的复合场景。在DCL单例中,volatile用于防止指令重排序导致的其他线程获取未初始化对象的问题。
Q&A
为什么在Android开发中需要使用Java多线程?
Java多线程可以提高CPU利用率,处理CPU、内存和IO设备之间的速度差异。
进程和线程有什么区别?
进程是正在运行的应用程序,而线程是应用程序中的执行路径,线程切换比进程更轻量,且线程可以共享资源。
多线程编程中常见的问题有哪些?
常见问题包括可见性、原子性和有序性,这些特性缺一不可会导致程序错误。
如何处理多线程中的可见性问题?
可以使用volatile、synchronized和final关键字来确保变量的可见性。
什么是Java内存模型(JMM)?
JMM定义了变量的存储和访问规则,确保Java程序在不同平台下的一致性,并处理可见性、原子性和有序性的问题。
volatile关键字的作用是什么?
volatile关键字确保变量的可见性,并防止指令重排序。