并发编程面试精讲:原子性、可见性与有序性

需积分: 0 0 下载量 174 浏览量 更新于2024-06-23 收藏 94KB DOCX 举报
"并发编程 48 道面试题及答案文档包含了关于并发编程的基础概念、面试常见问题以及解答,旨在帮助准备面试者理解和掌握并发编程的核心知识点。" 并发编程是多线程环境下保证程序正确性和高效运行的关键技术。在Java等编程语言中,有三个基本要素支撑并发编程: 1. **原子性**:原子性确保一个操作不会被其他操作打断,要么全部完成,要么完全不执行。Java中的`java.util.concurrent.atomic`包提供了一些原子变量类,如AtomicInteger,以支持原子操作。 2. **可见性**:可见性是指当一个线程修改了共享变量,其他线程能够立即看到这个修改。Java的`synchronized`关键字和`Lock`接口(如ReentrantLock)可以确保对共享变量的修改对所有线程可见。 3. **有序性**:有序性保证程序执行的顺序符合代码的逻辑顺序。Java内存模型(JMM)通过内存屏障和volatile关键字来维护有序性,防止编译器和处理器优化导致的乱序执行。 实现可见性有以下几种方法: - **synchronized**:同步块或同步方法可以保证在同一时刻只有一个线程执行,并且在退出同步代码块前将修改写回主内存,确保其他线程可见。 - **Lock**:如ReentrantLock,其lock和unlock操作具有类似synchronized的同步效果,同时提供了更细粒度的控制。 - **volatile**:标记为volatile的变量,其修改对所有线程都是立即可见的,避免了线程工作内存与主内存之间数据的延迟。 多线程编程的价值主要体现在: - **利用多核CPU**:在多核处理器系统中,多线程能充分利用硬件资源,提高程序的执行效率。 - **防止阻塞**:即使在一个单核CPU环境中,多线程也可以避免单个线程阻塞导致的整个程序停滞,提高程序的响应性。 - **便于建模**:复杂的任务可以通过拆分为多个线程来简化编程,每个线程专注于一小部分任务,简化了程序设计和调试。 创建线程有多种方式: - **继承Thread类**:直接扩展Thread类并重写run()方法,然后实例化并调用start()启动线程。 - **实现Runnable接口**:创建一个类实现Runnable接口,重写run()方法,然后将Runnable实例传递给Thread构造器启动线程。 - **实现Callable接口**:创建一个类实现Callable接口,重写call()方法,返回一个结果。Callable可以配合FutureTask或ExecutorService获取返回值。 - **使用线程池**:通过ExecutorService(如ThreadPoolExecutor)提交Runnable或Callable任务,线程池可以有效地管理和复用线程。 每种创建线程的方式都有其优缺点。例如,实现Runnable接口允许线程类与其他类继承,而继承Thread类则可能限制了类的继承性。使用线程池可以有效管理线程,减少线程创建和销毁的开销,提高性能。在实际开发中,通常推荐使用线程池,因为它更加高效和可控。