news 2026/10/9 3:29:47

多线程并发相关知识点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
多线程并发相关知识点

文章目录

      • 1、wait/sleep的区别:
      • 2、synchronized出现异常会释放锁?
      • 3、synchronized和Lock的区别?
      • 4、Runnable和Callable的区别?
      • 5、为什么内部类不能访问非final的局部变量?
      • 6、阻塞队列方法的区别?
      • 7、线程池详解
      • 8、自定义线程池时,我们如何确定线程池的最大线程数量?
      • 9、volatile如何保证可见性和有序性?
      • 10、synchronized详解
      • 11、JUC三大辅助类
      • 12、线程的状态
      • 13、产生死锁的四个必要条件:
      • 11、练习题
      • 12、基于ReentrantLock详解AQS
      • 13、CompleteFuture详解
      • 14、ThraedLocal

https://thinkwon.blog.csdn.net/article/details/104863992

1、wait/sleep的区别:

  1. 来自不同的类:
    wait => Object
    sleep => Thread
  2. 关于锁的释放:
    wait会释放锁,sleep不会释放锁
  3. 使用范围:
    wait必须在同步代码块中使用,而sleep可以在任何地方使用
  4. 是否需要捕获异常:
    wait需要捕获异常,sleep需要捕获异常
  5. 同:都是让线程进入等待状态。

2、synchronized出现异常会释放锁?

会释放。

3、synchronized和Lock的区别?

  • synchronized是关键字,Lock是接口;
  • synchronized是不可中断的,Lock是可中断的,也可以是不可中断的;
  • synchronized会自动释放锁,Lock锁需要手动释放锁;
  • synchronized是非公平锁,Lock锁可以是公平锁也可以是非公平锁‘;
  • Lock可以知道线程有没有获取锁,而synchronized不能;
  • synchronized可以锁代码块和方法,Lock锁只能锁代码块;

4、Runnable和Callable的区别?

  1. Callable有返回值,而Runnable没有返回值
  2. Callable可以抛出异常,而Runnable不能抛出异常
  3. Callable的方法是call(),而Runnable的方法是run()

为什么Runnable接口的run方法不能抛出异常,而必须捕获呢?

因为Runnable接口中的run方法没有抛出异常,所以子类在重写run方法时,不能抛出异常。

5、为什么内部类不能访问非final的局部变量?

局部变量的生命周期:当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。而内部类对象生命周期与其它类对象一样:自创建一个匿名内部类对象,系统为该对象分配内存,直到没有引用变量指向分配给该对象的内存,它才有可能会死亡(被JVM垃圾回收)。所以完全可能出现的一种情况是:成员方法已调用结束,局部变量已死亡,但匿名内部类的对象仍然活着。
1.局部变量和匿名内部类的生命周期不一致,所以匿名内部类会复制一份到匿名内部类中
2.之所以使用强制使用final修饰局部变量,是为了保证内外局部变量之间的数据一致性,至于使不使用final不重要,重要的是局部变量只有一次赋值,出现二次赋值立马就报错。

6、阻塞队列方法的区别?

阻塞队列的使用:

操作抛出异常有返回值(true/false)阻塞等待超时等待
添加add()offer()put()offer(E e, long timeout, TimeUnit unit)
移除remove()poll()take()poll(long timeout, TimeUnit unit)
获取队首元素element()peek()

当使用add()往一个满的队列中加入元素时,会抛出如下的异常:

抛出异常:

java.lang.IllegalStateException:Queuefull

当使用remove()移除一个空队列的元素时,或者使用element()获取一个空队列的队首元素时,会抛出如下异常:

队列为空:

java.util.NoSuchElementException

使用offer()往队列添加元素,添加成功返回true,队满添加失败,返回false。

使用poll()出队元素时,或者peek()获取队首元素时,如果元素存在,则返回元素,否则返回null。


当使用put()往队列添加元素时,如果队列不满则添加成功,否则会阻塞(一直阻塞)。

当使用take()出队元素时,如果队列有元素则出队,并返回该元素,如果队列为空,调用该方法则会阻塞(一直阻塞)。


offer(E e, long timeout, TimeUnit unit) 可以指定超时等待的时间,不会一直等待下去。

poll(long timeout, TimeUnit unit) 也一样。


7、线程池详解

https://blog.csdn.net/Linging_24/article/details/109401629

8、自定义线程池时,我们如何确定线程池的最大线程数量?

《Java并发编程实战》公式:最大线程数 = (CPU核心数 * CPU利用率) / (1 - 阻塞系数)。

阻塞系数:线程等待的时间占比 = 线程平均等待时间 / 线程平均等待时间 + 线程占用CPU时间

早期经验法则:

  1. CPU密集型:

    套入公式,对于CPU密集型任务,阻塞系数接近0,所以最大线程数 ≈ CPU核心数

    Runtime.getRuntime().availableProcessors();//获取CPU最大并行线程的数量。
  2. IO密集型:当时Web应用普遍I/O等待时间约为50%

    套入公式,最大线程数 = 2 * CPU核心数

  3. 混合型:
    介于cpu核心数和2*cpu核心数之间

现代演进实践:

  1. 计算密集型:线程数 = CPU核心数 + 1(或直接等于核心数)
  2. I/O密集型:使用上述公式作为起点,通过压测调整
  3. 混合型:通常取 2 × CPU核心数 到 公式计算值 之间

最大线程数调整流程:理论 => 压测 => 监控 + 动态调整

9、volatile如何保证可见性和有序性?

https://blog.csdn.net/bfj11/article/details/123949405
https://blog.csdn.net/jyxmust/article/details/76946283

有序性:(单核CPU)内存屏障 + 缓存一致性协议MESI(多核CPU)
可见性:内存屏障

内存屏障的两个作用:

  1. 禁止指令重排序
  2. 读写强刷,立即可见

10、synchronized详解

https://blog.csdn.net/Linging_24/article/details/110541592

11、JUC三大辅助类

  • CountDownLatch:实现让一个线程等待其他线程执行完毕后再执行。
  • CyclicBarrier:实现让一组线程等待至某一状态,再全部同时执行。
  • Semaphore:Semaphore 是 synchronized 的加强版,作用是控制线程的并发数量。

12、线程的状态

  • 新建状态:
    使用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序start()这个线程。

  • 就绪状态:
    当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

  • 运行状态:
    如果就绪状态的线程获取 CPU 资源,就可以执行run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

  • 阻塞状态:
    如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

    • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
    • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
    • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
  • 死亡状态:
    一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

13、产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

11、练习题

  1. 三个线程t1、t2、t3。确保三个线程,t1执行完后t2执行,t2执行完后t3执行。执行顺序:t1->t2->t3
1.Semaphore实现,初始凭证02.Lock+condition实现3.synchronized+wait+notifyAll实现4.join
  1. 三个线程t1、t2、t3。确保三个线程,t1,t2执行完,t3再执行
1.CountDownLatch实现2.join实现3.synchronized+wait+notifyAll实现4.Lock+condition实现
  1. 生产者消费者问题
1.synchronized+wait+notifyAll实现2.Lock+condition实现
  1. 多线程循环顺序打印:ABABABABAB,线程A打印A,线程B打印B。
1.synchronized+wait+notifyAll实现2.Lock+condition实现
  1. 多线程循环顺序打印:0102030405,线程0打印0,线程1打印奇数,线程2打印偶数
1.synchronized+wait+notifyAll实现2.Lock+condition实现

12、基于ReentrantLock详解AQS

https://blog.csdn.net/Linging_24/article/details/134961383

13、CompleteFuture详解

https://blog.csdn.net/Linging_24/article/details/144832725?spm=1001.2014.3001.5501

14、ThraedLocal

https://blog.csdn.net/Linging_24/article/details/109708451?spm=1001.2014.3001.5501

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 3:29:43

synchronized详解

文章目录1、并发编程会出现原子性、可见性、有序性问题。2、JVM内存模型3、主内存与工作内存的交互4、synchronized如何保证可见性、原子性、有序性?5、synchronized的特性5.1 可重入5.2 不可中断6、synchronized的原理(jdk1.6以前)6.1 synch…

作者头像 李华
网站建设 2026/10/9 3:29:09

CSS图片实例

本文目录1. 前言2. 普通图片3. 圆角图片4. 缩略图效果5.小结1. 前言 上一篇我们详细讲解了如何利用CSS,来制作一个好看的按钮。 本篇我们来研究下如何用CSS美化图片。 2. 普通图片 普通情况下,我们给图片设置个宽度和高度即可。 普通图片&#xff1a…

作者头像 李华
网站建设 2026/10/9 3:29:00

Django实战:42文件源码拆解课程推荐与智能问答系统

简介:这份资源是一套基于Python的实时课程教学数据内容推荐与个性化智能问答系统源码,面向教育技术方向的学习者、课程设计开发者及毕业设计选题人群,用于解决教学资源个性化推送与知识问答自动化的实现问题。压缩包共54个文件,约…

作者头像 李华
网站建设 2026/10/9 3:28:45

民航iOS技术栈与离线优先架构:从Swift到航班动态的工程实践

1. 民航场景让我重新理解了 iOS 技术栈很多人以为民航 App 就是另一个“航班查询工具”,真正做过之后才发现完全是另一回事。我在民航 IT 一线做了几年 iOS 开发,从旅客端到机组端都参与过,对这套业务有很深的体感。标题里说的“技术栈、架构…

作者头像 李华
网站建设 2026/10/9 3:28:45

子网DHCP实战:单台服务器为多VLAN分配IP的配置与地址池规划

1. 子网DHCP:为什么你的实验要玩“一拖多”很多朋友在ENSP里做DHCP实验,习惯性操作就是“一台路由器 两台PC”,然后接口模式下敲几条命令,PC自动获取到IP,实验结束。这套流程练熟之后,你会觉得DHCP不过如此…

作者头像 李华
网站建设 2026/10/9 3:28:41

Git Reset全面详解:三种模式与reflog救援实战

2. 前言:为什么 Git Reset 是开发者最该吃透的命令之一在Git的日常操作里,git reset绝对算得上使用频率最高、误操作后果最严重的命令之一。很多新手对它敬而远之,老手也常在紧急时刻因为记混参数而手忙脚乱。我见过不少团队因为一次随意的gi…

作者头像 李华