JUC多线程-线程池-Thredalocal-CAS-AQS-死锁

简介: JUC多线程-线程池-Thredalocal-CAS-AQS-死锁

一、多线程

1.进程和线程的区别

进程是系统运行的最小单位,一个java程序是一个进程,是互相独立的

线程是独立运行的最小单位,一个java程序可以有多个线程,线程之间可以共享数据

2.死锁的必要条件

互斥:同一资源同一时刻只能由一个程序读取

不可抢占:不能强行剥夺线程占有的资源

请求和保持:请求其他资源的时候对手中的资源保持不放

循环等待:互相等待的资源中,形成闭环

想要预防死锁,只需要破坏一个条件即可,例如使用定时锁

3.Synchronized和lock的区别

  1. Synchronized是关键字,lock是类
  2. syn会自动释放锁,lock需要手动释放
  3. syn是可重入锁、非公平锁、不可中断锁,lock的ReentrantLock是可重入锁,可以是公平锁也可以是非公平锁
  4. syn是jvm层面通过监视器实现的,lock是AQS实现的

4.什么是AQS

深入理解AQS队列同步器原理-从ReentrantLock的非公平独占锁实现来看AQS的原理

AQS是一个抽象类,可以用来构造所和同步类

原理

三个核心组件,一个是state代表加锁状态初始值为0,一个是获取到锁的线程,还有一个阻塞队列。当有线程想要获取锁的时候,会以CAS的形式将state变为1,CAS成功之后将加锁线程设为自己,当其他队列来竞争锁时会判断state是不是0,不是0再判断加锁线程是不是自己,不是自己就把自己放入阻塞队列,这个阻塞队列是双向链表实现的。

可重入锁的原理就是每次加锁时判断一下加锁线程是不是自己,是的话state+1,释放锁的时候就将state-1。当state减到0的时候就去唤醒阻塞队列的第一个线程。

5.slepp()和wait()的区别

  1. sleep是Thread的方法,wait是Object的方法
  2. sleep不会释放锁,wait会释放锁
  3. sleep没有限制,wait需要在同步方法或者同步代码块中执行
  4. sleep自动唤醒,wait需要调用notify或者notifyall唤醒

6.yield()和Join()的区别

yield调用后进入就绪状态

A线程调用B线程的join(),则B执行完前A进入阻塞状态

7.线程池七大参数

核心线程数:线程池中基本线程数量

最大线程数:当阻塞队列满了之后,逐一启动

最大线程的存活时间:当阻塞队列的任务执行完成后,最大线程的回收时间

最大线程的存活时间单位

阻塞队列:当核心线程满了后,后面来的任务进入阻塞队列

线程工厂:用于生产线程

任务拒绝策略:阻塞队列满了之后,拒绝任务的四种策略 (1)抛异常(2)丢弃任务不抛异常(3)打回任务(4)尝试与最老的线程竞争

8.JMM java内存模型

JMM屏蔽了各种硬件和操作系统的内存访问差异,实现java程序在各个平台下都能达到一致的内存访问效果,定义了JVM如何将程序的变量在主存中读取

定义:所有的变量都存在主存中,主存是线程共享区域;每个线程都有自己独立的工作内存,线程想要操作变量必须从主存中copy变量到自己的工作区,每个线程的工作内存都是互相隔离的

由于主存与工作内存之间有读写延迟,切读写不属于原子操作,所以会有线程安全问题

9.如何保证并发的三大特性

原子性:一次或多次操作在执行期间不能被其他线程影响

可以通过 synchronized和Lock实现原子性,volatile不能保证原子性。

可见性:当一个线程在工作内存修改了变量,其他线程应该立刻知道

volatile可以解决可见性问题(能否及时可见),不加volatile也可能可见,但不一定及时。synchronized和Lock也可以保证可见性,因为它们可以保证任一时刻只有一个线程能访问共享资源,并在其释放锁之前将修改的变量刷新到内存中。

有序性:JVM对指令的优化会让指令改变执行顺序,有序性是禁止指令重排序的

volatile可以保证可见性,禁止指令重排序(DCL需要添加volatile)。通过内存屏障实现。

10.ThreadLocal原理

为每个线程创建变量副本,不同线程之间不可见,保证线程的安全。每个线程内部维护一个Map,key作为threadloacl实例,value是保存的副本,使用threadlocal会造成内存泄漏,因为key是弱引用,value是强引用,每次gc的时候会回收key,value不会回收,可以每次使用完就删除value或者使用static修饰threadlocal解决内存泄露的问题

11.CAS锁和缺点

CAS可以保证原子性,思想是更新内存的时候判断是否被别人修改过,没有就直接更新。如果被修改了就要重新获取值,直到更新完成为止,缺点是

  1. 只能支持一个变量的原子操作,不能保证代码块的原子性
  2. CAS频繁导致CPU的开销大
  3. ABA问题:ab线程拿到a的值,a因为某种原因阻塞,b将值修改为其他值,又修改回来,如何成功退出,此刻a线程退出阻塞,查看值,发现还是之前的值,a没有发现值被修改了,这就是aba问题,可以通过增加版本号或者时间戳来解决

12.Synchronized锁原理和优化

syn是通过对象头的markwordk来表明监视器的,监视器本质是依赖操作系统的互斥锁实现的。操作系统实现线程切换需要从用户态转为内核态,成本很高,这种锁叫重量级锁,在JDK1.6之后引入了偏向锁、轻量级锁、重量级锁

偏向锁:当一个线程多次访问一段代码,都没有其他线程竞争,会获得偏向锁,偏向这段代码

轻量级锁:当锁是偏向锁的时候,有另外一个线程访问,会升级为轻量级锁,线程通过CAS获取锁,不会阻塞,提高性能

重量级锁:轻量级锁自旋一段时间还没有获取到锁,会升级为重量级锁,来竞争的线程都会阻塞,性能低下

注意:锁升级不是直接升级,需要经过自旋操作,只能升级不会降级

13. volatile 是什么?可以保证有序性吗?

一旦一个变量被volatile修饰,那么就具有两层语义

1)保证其他线程对这个操作的可见性,volatile修饰的变量被修改之后会被强制写入主存,其他线程立即可见

2)禁止指令重排序,局部有序性(前面的已经操作完成,后面的不能到volatiel前面来)

14.Thread 类中的start() 和 run() 方法有什么区别?

start()内部调用了run()方法,如果直接调用run那么还是单线程,调用start才是多线程

相关文章
|
4月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
163 0
|
23天前
|
缓存 安全 Java
JUC系列之《CountDownLatch:同步多线程的精准发令枪 》
CountDownLatch是Java并发编程中用于线程协调的同步工具,通过计数器实现等待机制。主线程等待多个工作线程完成任务后再继续执行,适用于资源初始化、高并发模拟等场景,具有高效、灵活、线程安全的特点,是JUC包中实用的核心组件之一。
|
22天前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
87 2
|
22天前
|
Java 测试技术 API
【JUC】(1)带你重新认识进程与线程!!让你深层次了解线程运行的睡眠与打断!!
JUC是什么?你可以说它就是研究Java方面的并发过程。本篇是JUC专栏的第一章!带你了解并行与并发、线程与程序、线程的启动与休眠、打断和等待!全是干货!快快快!
261 2
|
22天前
|
设计模式 消息中间件 安全
【JUC】(3)常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!文章全程笔记干货!!
JUC专栏第三篇,带你继续深入JUC! 本篇文章涵盖内容:保护性暂停、生产者与消费者、Park&unPark、线程转换条件、多把锁情况分析、可重入锁、顺序控制 笔记共享!!文章全程干货!
87 1
|
4月前
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
5月前
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
308 5
|
9月前
|
存储 监控 Java
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
384 60
【Java并发】【线程池】带你从0-1入门线程池
|
6月前
|
存储 缓存 安全
JUC并发—11.线程池源码分析
本文主要介绍了线程池的优势和JUC提供的线程池、ThreadPoolExecutor和Excutors创建的线程池、如何设计一个线程池、ThreadPoolExecutor线程池的执行流程、ThreadPoolExecutor的源码分析、如何合理设置线程池参数 + 定制线程池。
JUC并发—11.线程池源码分析
|
7月前
|
Java
线程池是什么?线程池在实际工作中的应用
总的来说,线程池是一种有效的多线程处理方式,它可以提高系统的性能和稳定性。在实际工作中,我们需要根据任务的特性和系统的硬件能力来合理设置线程池的大小,以达到最佳的效果。
179 18

热门文章

最新文章

下一篇
开通oss服务