Java 多线程 面试题

简介: Java 多线程 相关基础面试题

并发编程三要素?

  • 三要素主要包括可见性、原子性和有序性
  • 可见性:是指一个线程对共享变量的修改能够被其他线程立即看到的特性。
  • 原子性:是指一个或多个操作要么全部执行成功,要么全部执行失败,不会被其他因素打断。
  • 有序性:是指程序执行的顺序必须符合预期,不能出现乱序的情况。

同步方法和同步块哪个是更好的选择?

  • 如果业务需求简单,可以倾向于使用同步方法,因为它更简单直观。但如果需要更细粒度的锁控制,或者想要提高性能和减少死锁风险,同步块是更好的选择。

谈谈原子性?哪些使用到了?

  • 原子性:是指一个或多个操作要么全部执行成功,要么全部执行失败,且这个执行过程不会被其他线程打断或干扰。
  • 实现方式:
    • 使用synchronized关键字:
      • 通过在方法或代码块上使用synchronized关键字,可以确保同一时间只有一个线程能够执行该方法或代码块,从而实现原子性。但这种方式可能会导致线程阻塞和性能下降。
    • 使用原子类:
      • Java提供了java.util.concurrent.atomic包中的一系列原子类,如AtomicInteger、AtomicLong、AtomicBoolean等。这些类中的方法都是原子操作,内部使用了CAS(Compare and Swap)等底层机制来确保操作的原子性。这种方式比使用synchronized关键字更高效,因为它不会导致线程阻塞。
    • 使用Lock接口及其实现类:
      • Java还提供了Lock接口及其实现类(如ReentrantLock)来提供比synchronized更灵活的锁机制。通过显式地加锁和解锁,可以确保操作的原子性。但这种方式需要程序员自己管理锁的生命周期,增加了代码的复杂性。

谈谈可见性?哪些使用到了?

  • 可见性:是指当一个线程修改了共享变量的值时,这个新值对其他线程来说是可以立即得知的。
  • 可见性使用情况:
    • volatile关键字
    • synchronized关键字
    • final关键字
    • Locks和Condition
    • 原子变量类
    • 线程的启动和结束

谈谈有序性?举一个例子?

  • 有序性:是指多线程环境下,程序执行顺序的一种保障机制。

什么是线程池?

  • 线程池:是一种重用线程的机制,它可以在需要时创建线程,而不是每次都创建新的线程。
  • 线程池核心参数:最大线程数、拒绝策略、核心线程数、任务队列、线程空闲时间
  • 常见类型:固定大小线程池(FixedThreadPool)、缓存线程池(CachedThreadPool)、单线程池(SingleThreadPool)、定时线程池(ScheduledThreadPool)、工作窃取线程池

线程池有哪些创建方式?

  • 使用Executors工厂类
  • 直接使用ThreadPoolExecutor类
  • 使用Executors工厂方法的变体
  • 使用ForkJoinPool

谈谈四种线程池的创建?

  • Executors.newCachedThreadPool:创建一个可根据需要创建新线程的线程池,并允许自定义线程工厂。
  • Executors.newFixedThreadPool:创建一个可重用固定线程数的线程池,并允许自定义线程工厂。
  • Executors.newSingleThreadExecutor:创建一个只有一个线程的线程池,并允许自定义线程工厂。
  • Executors.newScheduledThreadPool:创建一个用于延迟执行或定期执行任务的线程池,并允许自定义线程工厂。

newCachedThreadPool?

  • 缓存线程池:不固定线程数量,可以根据需要自动创建新线程,适用于短期异步任务。

newFixedThreadPool ?

  • 固定大小线程池:包含固定数量的线程,适用于需要限制并发线程数量的场景。

newScheduledThreadPool ?

  • 定时线程池:可以执行定时任务和周期性任务。

newSingleThreadExecutor ?

  • 单线程池:只包含一个工作线程,保证所有任务按顺序执行,适用于需要保持任务顺序执行的场景。

多线程的优缺点?

  • 优点:提高性能、改善响应性、资源利用率高、并行处理、代码模块化、提高吞吐量
  • 缺点:复杂性增加、竞争条件、死锁、上下文切换开销、资源限制、调试困难、不可预测性、线程安全问题

创建线程的有哪些方式?

  • 继承Thread类、实现Runnable接口、使用Callable和Future创建、使用线程池

谈谈各种创建线程的优缺点?

  • 继承Thread类:
    • 优点:编写简单,容易理解
    • 缺点:由于单继承机制,如果类已经继承另一个类,则无法再继承Thread类
  • 实现Runnable接口:
    • 优点:避免了单继承限制,可实现多个接口。更加灵活,可使用lambda表达式、匿名内部类方式简化代码
    • 缺点:需手动管理线程的生命周期
  • 使用Callable和Future创建:
    • 优点:可获取线程的返回值。可声明抛出异常
    • 缺点:相比Runnable接口更加复杂,需配合FutureTask使用
  • 使用线程池:
    • 优点:提高线程的利用率和系统吞吐量。降低线程创建、销毁的开销。提供更好的线程管理策略,如线程服用、线程缓存等。
    • 确定:需理解线程池的工作原理和配置参数。需注意线程池的资源管理和关闭问题。

对比下你应该选择哪种创建?

  • 需要根据具体的应用场景和需求、编码规范来选择合适的方式。

Runnable和Callable的区别?

  • 核心方法差异:Runnable接口核心方法是run,Callable接口核心方法是call。
  • 使用场景差异:Runnable接口适用简单任务,这些任务不需要返回值,也不会抛出受检异常。Callable接口适用需要返回值的任务或需要抛出受检异常的任务。
  • 异常处理差异:Runnable接口无法对异常进行显式的捕获和处理异常。Callable可以抛出受检异常,可以显式的捕获和处理异常。
  • 与线程类的关系:Runnable接口可以作为Thread类的构造器参数,通过Thread类来启动线程。不能直接作为Thread类的构造器参数,需通过其他方式(FutureTask类)启动线程。

线程的状态流转图?有哪些状态?

  • 线程状态:NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(超时等待)、TERMINATED(终止)

线程池的优点?

  • 资源管理
  • 提高吞吐量
  • 性能提升
  • 减少上下文切换
  • 灵活性
  • 异常处理
  • 任务调度
  • 减少竞争

常用的并发集合类有哪些?

  • ConcurrentHashMap
  • ConcurrentLinkedQueue
  • BlockingQueue接口及其实现
  • CopyOnWriteArrayList
  • CopyOnWriteArraySet
  • ConcurrentSkipListMap
  • ConcurrentSkipListSet
  • AtomicReference
  • Collections.synchronizedMap、Collections.synchronizedList、Collections.synchronizedSet
  • Executor框架中的线程安全集合

ConcurrentHashMap实现?

  • 分段锁、cas操作和节点级锁定、红黑树优化、弱一致性、容量和负载因子、并发性能
  • 是在并发环境下提供高性能,通过减少锁的粒度来实现。
  • 使用分段锁实现线程安全。使用cas操作来更新结构,减少锁的使用,提高性能。读操作不需要加锁,减少读操作的开销。写操作尝试使用cas操作更新,更新失败,则使用synchronized锁住当前链表或红黑树的节点。遵循内存一致性原则,确保写操作完成后,后续的读操作能看到最新的值。

CopyOnWriteArrayList实现?

  • 主要用于读多写少的场景。
  • 数据结构底层使用数组。读操作不加锁,直接操作数组的快照。写操作会创建数组的新副本,在副本上执行修改操作,然后将原数组引用指向新副本。

CopyOnWriteArraySet实现?

  • 主要用于读多写少的场景。
  • 内部使用一个CopyOnWriteArrayList来存储元素。

谈谈COW?

  • COW(Copy-On-Write,写时复制)是一种用于优化并发访问的数据结构实现策略。
  • COW的基本思想是在进行写操作时,不直接修改原数据,而是先复制一份副本,然后在副本上进行修改。写操作完成后,再将副本替换为原数据。
  • COW实现的并发容器:CopyOnWriteArrayList和CopyOnWriteArraySet。
  • 优势:读操作无需加锁,提高读取效率。避免锁竞争和死锁。适用读多写少的场景。
  • 劣势:写操作内存开销大。极端情况下仍存在数据一致性问题。不适用写操作频繁的场景。

常用的并发工具类有哪些?

  • Executor框架:Executor接口、Executors工厂类、ExecutorService接口、ScheduledExecutorService接口、ForkJoinPool
  • 同步辅助工具:CountDownLatch、CyclicBarrier、Semaphore(控制同时访问特定资源的线程数量)、Exchanger(用于两个线程交换数据)、Phaser
  • 并发集合:ConcurrentHashMap、ConcurrentLinkedQueue、BlockingQueue接口、CopyOnWriteArrayList、CopyOnWriteArraySet
  • 原子变量类:AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference、AtomicStampedReference
  • 并发工具类:Future、FutureTask、Callable、Runnable、Lock、ReadWriteLock
  • 线程池管理工具:ThreadPoolExecutor
  • 同步器:ReentrantLock、ReentrantReadWriteLock

CyclicBarrier和CountDownLatch的应用场景?

  • CyclicBarrier:并行任务的等待、一次性事件触发、统计多个线程的执行时间。CyclicBarrier的计数器可以重置,因此可以在所有线程释放后,屏障再次用于下一轮的同步。它适用于需要多次等待多个线程完成任务的场景。
  • CountDownLatch:并行计算后的汇总、阶段任务同步、游戏或模拟中的回合制同步、批量处理。CountDownLatch的计数器只能减少,且一旦减为0就不能再次使用。它适用于一次性等待多个线程完成任务的场景。

CyclicBarrier和CountDownLatch的区别?

  • CyclicBarrier 适用于需要多个线程在某个点进行协作的场景,可以重复使用。
  • CountDownLatch 适用于一个线程等待其他线程完成任务的场景,使用后不能重用。

Semaphore的应用场景?

  • 适合于需要限制资源并发访问数量的场景。
  • 应用场景:控制并发访问、资源池管理、限流、线程执行顺序控制、互斥锁、实现生产者-消费者模式、保护共享资源

synchronized的作用?底层如何实现?

  • 作用:是一种同步机制,用于控制多个线程对共享资源的访问,以确保在任一时刻只有一个线程能够执行特定代码段,从而避免并发问题。
  • 底层实现:synchronized是通过Monitor(监视器)来实现的,Monitor是依赖于底层操作系统的互斥锁实现的。

synchronized和ReentrantLock的区别?

  • synchronized是java关键字,ReentrantLock是java的类。
  • synchronized:
    • 锁无需获取和释放
    • 只支持非公平锁
    • 可以修饰普通方法、静态方法、代码块
    • 低并发情况下,性能比ReentrantLock好
    • 底层是JVM层面通过Monitor(监视器)实现
  • reentrantLock:
    • 锁需手动获取和释放
    • 支持公平锁和非公平锁
    • 只能修饰代码块,但可以对代码块进行精细化的控制
    • 高并发情况下,性能通常比synchronized好
    • 底层基于AQS实现

volatile关键字的作用?底层如何实现?

  • 作用:
    • 用于确保变量的可见性和禁止指令重排。
    • 当一个变量被声明为volatile时,JVM保证了对该变量的读操作总是返回最新的值,即在任意线程中读取该变量时,都能得到该变量的最新值。
    • 写操作时,volatile变量的值会立即被更新到主内存中,且这个更新对所有线程都是可见的。
  • 底层实现:
    • volatile通过内存屏障实现内存可见性
    • 读操作前,插入Load Barrier,使得屏障之前的所有读/写操作都完成后,才执行该读操作
    • 写操作后,插入Store Barrier,使得屏障之后的写操作都完成后,才执行该操作

什么是CAS?底层如何实现?

  • CAS是Java并发编程中一种重要的原子操作,用于实现无锁编程。
  • 底层实现:
    • CAS的底层实现主要依赖于硬件提供的原子性操作指令和JNI(Java Native Interface)技术。
    • CAS操作通常通过Atomic类实现,类中的CAS方法底层用C语言编写,通过JNI技术调用本地方法实现

CAS有哪些问题?

  • ABA问题
    • 当一个线程准备用CAS更新一个变量的值时,另一个线程可能已经将该值从A改为了B,然后又改回了A。此时,第一个线程执行CAS操作时会认为值没有发生变化,从而成功更新值。
    • 解决办法:使用版本号、使用带有标记的原子引用
  • 循环时间长开销大
    • CAS操作是基于自旋锁的一种实现方式。如果CAS操作一直不成功,会导致线程长时间处于忙等(Busy-Wait)状态,从而消耗大量的CPU资源。
  • 只能保证一个共享变量的原子操作

synchronized、volatile、CAS比较?

  • synchronized:保证代码执行的原子性、可见性和有序性
  • volatile:用于修饰变量,确保变量的可见性,即一个线程修改了变量的值,新值对其他线程来说是立即可见的。
  • CAS:通过比较内存中的值和预期值是否相等,来安全地更新变量的值,通常用于实现原子类,如AtomicInteger。

什么是Future?底层如何实现?

  • Future是Java并发编程中的一个重要接口,它代表了异步计算的结果。
  • 底层实现:
    • Future是Java并发编程中的一个重要接口,它代表了异步计算的结果。
    • 通过调用Future对象的get()方法来获取任务的结果。
    • Future对象的状态管理通常依赖于AQS框架。
    • Future对象会捕获这个异常并保存在内部状态中。

什么是FutureTask?

  • FutureTask 是 Future 接口的一个实现类,同时也实现了 Runnable 接口,因此可以作为线程执行的任务。
  • 既可以作为 Future 的实现类来获取任务的执行结果,也可以作为线程执行的任务来执行异步操作。
  • FutureTask 允许在一个单独的线程中执行任务,并且可以获取任务的执行结果。

什么是AQS?底层如何实现?

  • AQS是Java并发包中的一个核心组件,是构建锁和其他同步器的基础框架。它定义了一套多线程访问共享资源的同步器框架,为Java并发同步组件提供统一的底层支持。
  • 底层实现:内部用一个volatile修饰的int类型的成员变量state来控制同步状态。state = 0表示没有线程正在独占共享资源的锁,state = 1表示有线程正在共享资源的锁

ReadWriteLock读写锁应用场景?

  • 应用场景:缓存场景、配置文件修改、共享文档操作、游戏状态管理、社交软件场景
  • ReadWriteLock读写锁适用于读多写少的并发场景,通过允许多个线程同时读取共享资源,可以显著提高系统的并发性能。

ReadWriteLock底层实现?

  • ReentrantReadWriteLock的底层实现是通过AQS来管理锁的状态和同步操作的。
  • 通过将state变量按位拆分来区分读锁和写锁的状态,并提供了读锁和写锁的获取与释放、公平性策略、锁降级等丰富的功能。

ThreadLocal是什么?底层如何实现?

  • ThreadLocal是Java提供的一个用于创建线程局部变量的机制,它能够为每个使用该变量的线程提供一个独立的变量副本,从而实现了变量的线程隔离。
  • 底层实现:
    • 依赖于Thread类和ThreadLocalMap类。
    • 通过ThreadLocalMap为每个线程提供了独立的变量副本,从而实现了变量的线程隔离。

死锁的常见原因有哪些?

  • Java死锁的常见原因涉及多个方面,包括竞争系统资源、锁的嵌套与不当的申请顺序、线程间相互等待、锁失效、饥饿与资源分配不均等。

如何避免死锁?有哪些解决方案?

  • 避免同时锁定多个资源
  • 使用定时锁
  • 使用超时锁定
  • 顺序锁定资源
  • 减少锁的粒度
  • 使用并发控制工具
  • 检测死锁
  • 避免嵌套锁定
  • 使用不可变对象
  • 死锁恢复策略

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

  • 使用wait()和notify()/notifyall()
  • 使用Lock和Condition
  • 改变线程等待的条件
  • 使用中断机制

什么是多线程的上下文切换?

  • 在多个线程之间进行切换的过程
  • 切换原因:
    • 线程阻塞:当一个线程等待I/O操作、获取同步锁或调用某些会挂起线程的方法时,操作系统可能会挂起该线程,并进行上下文切换以运行其他线程。
    • 线程结束:当一个线程执行完毕时,操作系统会进行上下文切换,将CPU控制权交给其他线程。
    • 时间片耗尽:在采用时间片轮转调度的系统中,当一个线程使用完其分配的时间片后,如果它还没有完成执行,操作系统会挂起该线程,并进行上下文切换以运行其他线程。
    • 线程优先级改变:如果一个高优先级的线程变为可运行状态,操作系统可能会挂起当前线程,并进行上下文切换以运行高优先级的线程。

线程调度算法是什么?

  • 是指Java虚拟机(JVM)用来决定哪个线程应该获得CPU资源以执行其任务的规则和策略。
  • 主要调度算法:
    • 时间片轮转调度:系统会为每个线程分配一个固定的时间片,在时间片内,线程可以正常执行。当时间片用完时,如果线程还没有执行完,CPU将把控制权交给下一个线程。
    • 抢占式调度:抢占式调度意味着线程的执行顺序并不是按照先到先得的原则,而是由线程的优先级决定。
    • 协同式调度
    • 多级反馈队列调度

什么是线程调度器和时间分片?

  • 线程调度器:是操作系统或Java虚拟机(JVM)的一部分,负责决定在多线程环境中,哪个线程应该获得CPU时间并执行。
  • 时间分片:时间分片是线程调度中的一个关键概念,它指的是将CPU时间划分成若干个小时间段(即时间片),并轮流分配给每个线程执行。

单例模式的线程安全性?

  • 在多线程环境中,如果多个线程同时访问单例类的实例化代码块,可能会创建多个实例,这违反了单例模式的原则。
  • 单例模式的线程安全实现:
    • 懒汉式:这种方式通过将getInstance方法声明为 synchronized来确保线程安全,但每次调用都会进行同步,性能较低。
    • 双重检查锁定:这种方式只在实例化时进行同步,减少了同步的开销。volatile关键字确保了instance变量的可见性和禁止指令重排。
    • 饿汉式:这种方式在类加载时就完成了实例化,因此是线程安全的,但可能会造成资源的浪费,因为实例可能一直未被使用。
    • 静态内部类:这种方式利用了Java的类加载机制来保证线程安全。SingletonHolder类在第一次被访问时才加载,JVM保证了SingletonHolder类的加载过程是线程安全的。
    • 枚举:枚举类型本身就是线程安全的,并且可以防止反序列化重新创建新的对象。

Executors是什么?

  • Executors是一个工具类,提供一系列静态工厂方法,用于快速创建和管理线程池。
  • 提供四种线程池类型:固定大小线程池、缓存线程池、单线程池、定时线程池

谈谈ExecutorService,ScheduledExecutorService?

  • 是concurrent包中提供的两个接口,用于异步执行任务。
  • ExecutorServivice:
    • ExecutorService是一个执行器服务,允许你异步地执行任务。
    • 特点:任务提交、线程池管理、关闭和终止、返回结果和异常处理。
  • ScheduledExecutorService:
    • ScheduledExecutorService是ExecutorService的子接口,它增加了定时任务和周期性任务的执行能力。
    • 特点:定时任务、周期性任务、单次调度和固定频率调度。
相关文章
|
6天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
随着云计算和DevOps的兴起,容器技术和自动化在软件开发中扮演着愈发重要的角色,但也带来了新的安全挑战。阿里云针对这些挑战,组织了一场关于云上安全的深度访谈,邀请了内部专家穆寰、匡大虎和黄竹刚,深入探讨了容器安全与软件供应链安全的关系,分析了当前的安全隐患及应对策略,并介绍了阿里云提供的安全解决方案,包括容器镜像服务ACR、容器服务ACK、网格服务ASM等,旨在帮助企业构建涵盖整个软件开发生命周期的安全防护体系。通过加强基础设施安全性、技术创新以及倡导协同安全理念,阿里云致力于与客户共同建设更加安全可靠的软件供应链环境。
125273 10
|
14天前
|
弹性计算 人工智能 安全
对话 | ECS如何构筑企业上云的第一道安全防线
随着中小企业加速上云,数据泄露、网络攻击等安全威胁日益严重。阿里云推出深度访谈栏目,汇聚产品技术专家,探讨云上安全问题及应对策略。首期节目聚焦ECS安全性,提出三道防线:数据安全、网络安全和身份认证与权限管理,确保用户在云端的数据主权和业务稳定。此外,阿里云还推出了“ECS 99套餐”,以高性价比提供全面的安全保障,帮助中小企业安全上云。
201925 14
对话 | ECS如何构筑企业上云的第一道安全防线
|
3天前
|
供应链 监控 安全
|
6天前
|
SQL 安全 前端开发
预编译为什么能防止SQL注入?
SQL注入是Web应用中常见的安全威胁,攻击者通过构造恶意输入执行未授权的SQL命令。预编译语句(Prepared Statements)是一种有效防御手段,它将SQL代码与数据分离,确保用户输入不会被解释为SQL代码的一部分。本文详细介绍了SQL注入的危害、预编译语句的工作机制,并结合实际案例和多语言代码示例,展示了如何使用预编译语句防止SQL注入,强调了其在提升安全性和性能方面的重要性。
|
9天前
|
搜索推荐 物联网 PyTorch
Qwen2.5-7B-Instruct Lora 微调
本教程介绍如何基于Transformers和PEFT框架对Qwen2.5-7B-Instruct模型进行LoRA微调。
417 34
Qwen2.5-7B-Instruct Lora 微调
|
1月前
|
人工智能 自然语言处理 前端开发
从0开始打造一款APP:前端+搭建本机服务,定制暖冬卫衣先到先得
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。
9940 29
|
3天前
|
机器学习/深度学习 存储 人工智能
【科普向】我们所说的AI模型训练到底在训练什么?
人工智能(AI)模型训练类似于厨师通过反复实践来掌握烹饪技巧。它通过大量数据输入,自动优化内部参数(如神经网络中的权重和偏置),以最小化预测误差或损失函数,使模型在面对新数据时更加准确。训练过程包括前向传播、计算损失、反向传播和更新权重等步骤,最终生成权重文件保存模型参数,用于后续的应用和部署。理解生物神经网络的工作原理为人工神经网络的设计提供了灵感,后者广泛应用于图像识别、自然语言处理等领域。
|
2天前
|
人工智能 算法 搜索推荐
阿里云百炼xWaytoAGI共学课开课:手把手学AI,大咖带你从零搭建AI应用
阿里云百炼xWaytoAGI共学课开课啦。大咖带你从零搭建AI应用,玩转阿里云百炼大模型平台。3天课程,涵盖企业级文本知识库案例、多模态交互应用实操等,适合有开发经验的企业或独立开发者。直播时间:2025年1月7日-9日 20:00,地点:阿里云/WaytoAGI微信视频号。参与课程可赢取定制保温杯、雨伞及磁吸充电宝等奖品。欢迎加入钉钉共学群(群号:101765012406),与百万开发者共学、共享、共实践!
|
15天前
|
机器学习/深度学习 人工智能 安全
通义视觉推理大模型QVQ-72B-preview重磅上线
Qwen团队推出了新成员QVQ-72B-preview,这是一个专注于提升视觉推理能力的实验性研究模型。提升了视觉表示的效率和准确性。它在多模态评测集如MMMU、MathVista和MathVision上表现出色,尤其在数学推理任务中取得了显著进步。尽管如此,该模型仍存在一些局限性,仍在学习和完善中。

热门文章

最新文章

下一篇
开通oss服务