2.Java面试题—并发基础、【同步 & 互斥】、JUC & 并发容器、【线程池】、【Lambda表达式】、方法引用、Stream流

本文目录如下:

四、并发编程

Java多线程学习 (吐血超详细总结) 🧐🧐🧐

一、并发基础

线程 和 进程 的区别?

  • 进程 是程序的一次 执行过程,是 程序执行资源分配 的基本单位。
  • 线程 是一个比 进程 更小的 执行单位,多个 线程 共享 进程堆、方法区 资源,线程切换 效率更高。
    每个线程 有自己的 程序计数器虚拟机栈本地方法栈

Java 中,启动 main 函数 就相当于启动了一个 JVM 的进程,而 main 函数 所在的 线程 就是这个进程中的 一个线程,也称 主线程


线程 有哪些状态 [理解至上]?

Java多线程学习 (吐血超详细总结) 🧐🧐🧐

  • 新建状态:线程对象被 创建 后,就进入了 新建状态
  • 就绪状态:线程对象调用 start()方法线程获取到锁 后进入了 就绪状态,等待 分配CPU
  • 运行状态就绪状态 的线程 获取了CPU,开始 执行代码。
  • 阻塞状态:阻塞的情况分三种:
    • 1、同步阻塞:线程执行 synchronizednotify() 后但是 没有获取到锁 进入 同步阻塞
    • 2、等待阻塞:线程执行 wait()方法 后进入 等待阻塞
    • 3、定时阻塞:线程执行 sleep()join()方法 后进入 阻塞状态
  • 终止状态
    在这里插入图片描述

Java 线程的六种状态?

Java 线程的几种状态

  • 新建状态
  • 可运行状态:包括 就绪运行 两个状态。
  • 阻塞状态:【同步阻塞
  • 等待状态:【等待阻塞
  • 定时等待状态:【定时阻塞
  • 终止状态

项目中哪些地方用到了多线程?

  • 异步处理发短信发邮件 等。
  • 批量处理
  • 定时任务

创建线程有哪几种方式?

  • 继承Thread类: 重写 run()方法
  • 实现Runnable接口: 重写 run()方法
  • 实现Callabe接口: 重写 call()方法, 该接口有 返回值

实现Runnable接口 比 继承Thread类 有哪些优势?

Java多线程学习 (吐血超详细总结) 🧐🧐🧐

  • 可以避免 Java 中的 单继承限制
  • 线程池 只能放入实现 Runable接口Callable接口 的线程,不能直接放入继承 Thread类 的线程。

线程的 run()和 start() 有什么区别?

  • run(): 线程体。它包含了线程要执行的内容。
  • start(): 创建 新的线程,并且执行在 run()方法 里的代码。

直接调用 run()方法,只会把 run()方法 当作 普通方法 去执行。


线程 之间如何通信?

Java线程间通信有多少种方法

  • 锁与同步 (ReentrantLock + Condition)
  • 等待/通知机制 (synchronized + wait() + notify())
  • 信号量: 点击查看
  • 共享内存

什么是 死锁?如何 预防死锁?

死锁 是指 两个以上的进程 在运行时,由于 竞争资源 而造成的一种 互相等待 的现象,若无外力干预,它们都将无法推进下去。


预防死锁,只需要破坏 死锁 的产生的 必要条件 即可:

  • 破坏请求与保持条件线程执行前 一次性申请 所有的资源
  • 破坏不可剥夺条件:如果申请不到 所有资源,就要 主动释放 已占有的资源。

二、同步 & 互斥【重要】

1、线程调度

多线程 如何保证 线程安全?
  • 手动锁 + 同步 (ReentrantLock + Condition)
  • 自动锁 + 同步 (synchronized + wait() + notify())
  • 线程安全类:如 VectorHashtableConcurrentHashMap等。

sleep() 和 wait() 有什么区别?

说说sleep和 wait有什么区别

  • sleep() 是使线程 休眠不会释放对象的锁
  • wait() 是使线程 等待释放对象的锁
  • sleep()线程 进入 定时阻塞 状态,wait()线程 进入 等待阻塞 状态。
  • sleep()Thread类方法wait()Object类方法

sleep()方法 和 yield()方法 有什么区别?

作用:都是 暂停线程,释放 CPU,使得其他线程能够访问。

  • sleep() 等到 睡眠时间结束 可进入 就绪状态yield() 释放 CPU 后立即进入 就绪状态
  • sleep() 给其他线程运行机会时 不考虑线程的优先级
  • yield() 只会给 相同优先级更高优先级 的线程以运行的机会;

3、synchronized 关键字

synchronized 是什么?有什么用?

Java基础——Synchronized用法

  • synchronizedJava 中的一个 关键字
  • synchronized 可以保证被它修饰的 方法代码块 在任意时刻只能有 一个线程执行

synchronized 作用于 普通方法、静态方法、代码块 有哪些区别?

主要区别在于 锁的对象 不同:
在这里插入图片描述


synchronized 实现原理?
  • synchronized 的内部是基于 JVM内置锁 实现的。
  • 当一个线程进入一个 synchronized 区域时,需要先获取 JVM内置锁,并在结束时 自动释放锁

同步方法 和 同步块,哪个是更好的选择?
  • 同步块 是更好的选择,因为它 不会锁住 当前对象,而是锁住 传入的对象。(也可以让它锁 当前对象)
  • 同步方法 会锁住 当前对象 (锁住 当前对象 中全部 同步块同步方法)。

4、volatile 关键字 & ThreadLocal

volatile 关键字有什么作用?

volatile 关键字 主要用于保证 变量可见性有序性

  • 可见性变量volatile 修饰时,它会保证 修改的值 会立即更新到 主存其他线程 可以立即读取到 最新的值
  • 有序性:被 volatile 修饰的 变量 不会被 重排序

volatile 使用场景?
  • 多个线程读,一个线程写的场合:一个线程在修改 volatile 变量 时,其他线程 能够立即看到 最新结果
  • 作为标记使用

synchronized 和 volatile 有什么区别?
  • 位置不同synchronized 可以修饰 方法、代码块volatile 只能给修饰 变量
  • 效率不同synchronized 可能导致 线程阻塞;volatile 不会造成 线程阻塞

synchronized 和 Lock 有什么区别 (谈谈 Java 中的 synchronized 关键字)?
  • synchronized 可以给 方法、代码块 加锁;Lock 只能给 代码块 加锁。
  • synchronized 不需要手动 管理锁不会造成死锁Lock 需要 手动管理锁,使用不当会 造成死锁

synchronizedJava 内置 同步机制关键字Lock 是个 Java接口


ThreadLocal 有什么作用?

ThreadLocal使用与原理

访问 ThreadLocal变量每个线程 都会有一个这个变量的 本地拷贝,不会影响其他线程的 局部变量,实现了线程的 数据隔离

  • 原理ThreadLocal 在内部使用一个类似于 MapThreadLocalMap 来存储 每个线程变量副本
  • 注意ThreadLocal 局部变量 使用结束后,需要手动 remove 删除,否则会造成 内存泄漏

三、JUC、并发容器

什么是 JUC?

JUC 指的是 Java并发工具包 (java.util.Concurrent),提供了多种 线程同步线程通信工具类JUC 提供了一系列 线程安全工具

  • 手动锁 + 同步 (ReentrantLock + Condition)
  • 自动锁 + 同步 (synchronized + wait() + notify())
  • 线程安全类:如 VectorHashtableConcurrentHashMap等。
  • 线程池工具类

什么是 公平锁、非公平锁?

Java并发–可重入锁、读写锁、(非)公平锁都怎么用

  • 公平锁: 线程 按照申请锁的顺序获取锁
  • 非公平锁: 线程 不按照申请锁的顺序获取锁
    `

sychronized 只支持 非公平锁ReentrantLock 默认非公平锁,但是支持 公平锁


什么是 可重入锁?Java中有哪些可重入锁?

究竟什么是可重入锁?

可重入锁 也叫 递归锁: 可递归调用,在 外层 获取 对象的锁 之后,内层 仍然可以 再次获得该对象的锁,并且 不发生死锁

  • 可重入锁LockReentrantLocksynchronized 都是 可重入锁
public class MyReentrant{
    Lock lock = new Lock();
    public void outer(){
        lock.lock();
        inner();           // inner() 函数中也有加锁释放锁的行为
        lock.unlock();     // 调用结束后仍可以继续执行本函数
    }
    public void inner(){
        lock.lock();
        //do something
        lock.unlock();
    }
}

什么是 CAS (典型的 乐观锁)?

Java–CAS的原理和优缺点
点击查看

  • CAS(Compare And Swap):是一种 乐观锁 机制,通过比较 内存中的值期望值 是否相等来确定 是否执行交换操作
  • 优点:性能很高。缺点:如果 冲突频繁,则 CPU 占用很高。

ReentrantLock 是什么?

ReentrantLock 是如何实现锁公平和非公平性的?

  • ReentrantLockLock 接口 的一个 具体实现类,是一个 可重入锁,同时也实现了 公平锁 机制。
  • ReentrantLock 内部使用了 AQS 来实现 锁资源的竞争,从而保证了 公平性

什么是 AQS 锁机制?

Java–AQS的原理

  • AQSJDK 自带的 锁机制,用于实现 公平锁
  • AQS原理:线程通过 CAS 竞争 锁资源,没有竞争到 锁资源 的线程,会加入到 AQS的同步队列 里面,通过 自旋 不断地 尝试获取锁
  • AQS的同步队列 是一个 虚拟的双向队列不存在队列实例,仅保存节点之间的 关联关系
    在这里插入图片描述

Java 中有哪些原子类?

Java–原子类(atomic)的用法(有实例)

基本类型

  • AtomicInteger
  • AtomicLong

数组类型:

  • AtomicIntegerArray
  • AtomicLongArray

四、线程池 【重要】

手动实现简单线程池

什么是线程池? 线程池有什么优点?

Java线程池总结

什么是线程池:

  • 线程池管理 多个 线程 的池子, 线程池 里的 线程 不断地从 任务队列 中取出 任务 执行。
  • 高并发场景下 大量 创建线程 很费时, 使用 线程池 可以 提高响应速度。

线程池的优点:

  • 提高响应速度:高并发场景下 大量 创建线程 很费时, 使用 线程池 可以 提高响应速度
  • 统一的连接管理: 提高 线程可管理性

说说 Java 线程池主要参数?

面试必备:Java线程池解析

线程池可以通过 ThreadPoolExecutor 来创建,核心参数有:

  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数
  • workQueue 存放任务的 阻塞队列
  • handler 线程池的 饱和策略

不重要的参数:

  • keepAliveTime:非核心线程的 存活时间
  • unit: 指定 keepAliveTime时间单位

Java 有哪几种常见的线程池?

Java线程池系列–线程池的种类

  • FixedThreadPool固定大小 的线程池。
  • SingleThreadExecutor单线程 的线程池。
  • CachedThreadPool可缓存 线程池。
  • ScheduleThreadPool可定时 的线程池。
种类核心线程数最大线程数队列长度描述
FixedThreadPoolnn无限/
SingleThreadExecutor11无限/
CachedThreadPool0无限0动态增删线程
ScheduleThreadPooln无限无限周期性执行任务

常见线程池的应用场景?

  • FixedThreadPool:适用于 负载稳定任务数量可预知 的场景。
  • CachedThreadPool:适用于 负载不稳定,可能会有 负载高峰 的场景。
  • SingleThreadExecutor:适用于 按顺序执行任务 的场景,任务会按照 提交顺序 执行。

什么是阻塞队列? 常见的 阻塞队列 有哪几种?

面试必备:Java线程池解析

阻塞队列 (BlockingQueue):在 普通队列 上增加了 两个操作:

  • 1.在队列为空时: 获取元素的线程会 等待 队列变为非空。
  • 2.当队列满时: 存储元素的线程会 等待 队列可用。
    阻塞队列 中的 线程任务 都是 Runnable接口 类型的,因为 executor.execute() 的参数类型只能是 Runnable接口

常见的 阻塞队列:

  • LinkedBlockingQueue: 基于 链表无界阻塞队列,容量为 Integer.MAX_VALUE
    FixedThreadPool、SingleThreadExecutor 使用】
  • SynchronousQueue: 无缓冲阻塞队列 (同步队列)。
    CachedThreadPool 使用】
  • DelayedWorkQueue: 支持 延时获取数据阻塞队列
    ScheduledThreadPool 使用】

常用的 线程池 的 拒绝策略 有哪些?默认是哪个?

饱和策略说明
AbortPolicy(默认策略) 丢弃此任务,抛出异常
DiscardPolicy丢弃此任务, 不抛出异常
DiscardOldestPolicy从队列里 删除最老的任务

线程池 中的 核心线程 和 非核心线程 有什么区别?

  • 核心线程: 线程池中 始终存在 的线程,
  • 非核心线程:当 任务数量 超过了 核心线程 数量,并且 阻塞队列 满时,才会创建的线程就是 非核心线程

什么时候触发 拒绝策略 | 线程任务 的 分配步骤?

在这里插入图片描述


CPU密集 与 IO密集 场景如何设置 核心线程数量?

  • CPU密集型核心线程数 = CPU核数 + 1
  • IO密集型核心线程数 = CPU核数 * 2 + 1
  • +1的原因:一个 额外 的线程,可以确保 CPU 不会 中断工作

如果任务 被阻塞的时间 大于 执行时间,即 IO密集型 任务,就需要创建 比处理器核心数大几倍数量的线程


ThreadPoolExecutor 和 Executors 有什么区别?

线程池ThreadPoolExecutor和Executors详解

  • ThreadPoolExecutor 是创建 自定义线程池
  • Executors 是用于创建 常见线程池 的工具类,不能实例化

线程池中 submit() 和 execute()方法有什么区别?

点击查看

  • execute(Runnable x)没有返回值无法判断 任务 是否成功完成
  • submit(Callable x):提供 Future 类型的 返回值。可以用来判断 任务是否成功完成

六、Java8新特性 - Lambda表达式、方法引用、Stream流

1 Lambda表达式【重要】

什么是 Lambda表达式

  • Lambda 表达式 是一种 轻量级匿名函数。它的本质就是一个 语法糖,可以用 更少的代码 来实现 同样的功能,程序 编译 时,由 编译器 转换为 常规的代码
  • Lambda 表达式 的形式为:(参数) -> Java表达式

Lambda表达式 使用案例?

Lambda表达式 使用案例

  • 如果 接口 内部只有 一个方法,则可以用 Lambda表达式实例化接口,其中,Lambda表达式 的作用是 重写接口的方法
  • 如果 方法参数只包含一个方法的接口,则可以直接用 Lambda表达式 作为该方法的入参。再简单一点,可以使用 方法引用

2 方法引用

什么是 方法引用?

  • 方法引用:是一种快速简便地将 现有方法 转换为 Lambda 表达式 的方式。
  • 它可以使 代码 更加 简洁易懂减少重复性的代码,提高代码的 可读性可维护性

方法引用 使用案例?

方法引用 使用案例


3 Stream流

Java–Stream流详解

什么是 Stream流?

Stream 是一个 高效易于使用集合处理数据方式

  • 可以进行复杂的 集合数据操作,比如 查找过滤映射 等。
  • 不直接修改 源数据,而是生成 新的 数据集合。

Stream流 使用案例?

List<Student> students = new ArrayList<>();
// ...

// 获取所有学生的姓名
List<String> tmpList1 = students.stream().map(s -> s.getName()).collect(Collectors.toList());

// 获取所有学生的姓名和年龄
List<People> tmpList2 = students.stream().map(s -> new People(s.getName(), s.getAge)).collect(Collectors.toList());

// 筛选年龄 大于16岁 的学生
List<Student> tmpList3 = students.stream().filter(s -> s.getAge() > 16).collect(Collectors.toList());

(了解) 常用中间操作符

Java–Stream流详解
在这里插入图片描述

(了解) 常用终端操作符

Java–Stream流详解
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

页川叶川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值