多线程专题(上)学习随手笔记

news2024/11/25 12:22:00
  1. JMM:主内存物理内存线程共享,工作内存CPU缓存线程独占
  2. volatile:可见性、禁止指令重排,不可保证原子性;用于懒汉单例模式(双重检测)或状态标记
  3. Synchronized:保证代码块或方法同步化执行,可以对当前类(class)对象(静态方法或静态对象)或对象加锁(同步代码块和非静态方法),若修饰多个方法时,也只能被一个线程调用;有锁的升级,偏向锁,轻量级锁,重量级锁;锁的消除(需开启逃逸分析);synchronized可对字符串加锁,若字符串对象是new String()或者StringBuilder生成的则是会创建不同的对象,不能充当对象锁
  4. Synchronized:两个指令monitor enter获取monitor对象、当monitor的count为0时,即可解除当前对象的锁,执行monitor exit命令释放锁
  5. 偏向锁,轻量级锁,重量级锁:偏向锁会在对象头Markword记录占有偏向锁的线程id,此时该线程执行同步代码块时不需要加锁和释放锁;若有线程竞争该锁并获取不到,就升级为轻量级锁,竞争该锁的线程进行自旋尝试获取锁;自旋达到一定次数时,会升级为重量级锁,竞争锁的线程会被挂起。(线程上下文切换很消耗资源)
  6. 对象的组成结构:对象头、实例数据、对齐填充(8个字节的整数倍,关于存储效率)
    1. 对象头:Mark Word、Klass Pointer类型指针、数组长度

    2. Mark Word:锁的状态、是否偏向锁、偏向锁的线程Id、GC分代年龄、hashcode、指针

  7. 锁的消除:利用逃逸分析,认定对象不会被其他线程访问,可以不考虑同步问题,消除不可能存在资源竞争的锁,节省毫无意义的请求锁的时间。
  8. ReentrantLock:可重入、公平或非公平、等待可中断、手动加解锁
  9. ReentrantLock用法:1.默认是非公平锁、2.加锁多少次就要解锁多少次、3.解锁unlock()要写在finally中,避免其他线程获取不到锁而阻塞、4.加锁lock()写在try块的前一行,而不写在try中,因为若try中的加锁操作出现异常,就执行解锁,但是持有锁的线程非当前线程,所以解锁操作会抛出异常
  10. AQS:可重入、公平\非公平、可中断、独占\共享、阻塞等待队列
  11. AQS(AbstractQueuedSynchronizer),抽象同步框架,当共享资源空闲时,请求资源的线程可以去占有并将共享资源锁住,用同步等待队列(CLH)将其他线程排队等待获取锁并阻塞线程,当占有资源的锁被释放时又可以从同步等待队列中唤醒线程去获取资源。很多并发工具类如ReentrantLock、Semophore、CountDownLetch、CyclicBarrier都是基于继承AQS实现功能。同步等待队列是基于双向链表实现的先进先出队列,会将等待锁的线程和等待状态封装成一node节点并加入队列。
  12. AQS定义了队列中节点的5种状态:0等待获取锁;1CANCELLED表示当前线程被取消;-1SIGNAL表示当前线程要被唤醒;-2CONDITION,表示线程在条件队列中;-3表示当前场景下后续的acquireShared能够得以执行;
  13. ReentrantLock源码:继承AQS抽象类,通过自旋、CAS获取释放锁、同步等待队列、LockSupport(用于将线程阻塞、唤醒)
  14. ReentrantLock的加锁逻辑:1.先尝试去获取锁,用CAS更改状态0到1,若修改成功则代表获取到锁并记录占有该锁的线程;若锁被占有了,看是否是当前线程占有,线程可以重复占有锁,锁状态用CAS加1;2.若获取锁失败,则将线程对象封装成节点并用自旋和CAS插入队列尾部,如果节点是队列的头节点,则再让该线程尝试获取锁,获取到锁则将节点从队列中移除,仍获取不到锁则将线程阻塞。
  15. 理解线程堵塞等待锁时被thread2.interrupt()中断唤醒线程去获取锁,然后有中断标识接着获取到锁后再次currentThread.interrupt(), 目的是为了将中断原因抛出去
  16. ReentrantLock的lockInterruptibly(),与lock()区别在于,lockInterruptibly()方法中线程发生中断会终止去获取锁,而lock()仍旧会等待获取锁但最终会把中断原因异常抛出去
  17. ReentrantLock的解锁逻辑:判断占有锁的线程是否为当前线程,否则抛出异常,将锁状态减1,若为0则将占有锁的线程移除,然后将队列的头节点移除并唤醒unpark()头节点的线程
  18. ReentrantReadWriteLock的读写锁,适用于读多写少场景,如读写缓存,但可能造成写锁饥饿(写锁一直等待读锁释放)。写锁是独占锁,读锁是共享锁;写锁优先于读锁、读锁会阻塞写锁、写锁会阻塞写锁和读锁、读锁不会阻塞读锁,获取读锁时会判断是否存在写锁和写锁是否是当前线程占有
  19. 锁的升级或降级,用于一个线程中又读又写的场景,升级:读锁变写锁,ReentrantReadWriteLock不支持锁升级,会导致死锁,因为写锁时要求不存在读锁;降级:写锁变为读锁,ReentrantReadWriteLock支持锁降级。锁降级的存在意义:再写完再读场景中,若全程都用写锁,性能消耗大,若是写完释放锁再读,则读取到数据可能不一致,其他线程会写入修改数据。
  20. StampedLock邮戳锁JDK1.8,对ReentrantReadWriteLock再优化,三种模式(读锁、写锁、乐观锁),支持锁的升级和降级。使用读操作用乐观锁lock.tryOptimisticRead(),再判断lock.validate(stamp),若校验不对则再用读锁,乐观锁即是无锁。StampedLock是不可重入锁,若一个线程持有写锁再重新获取则会死锁。
  21. Semaphore:信号量,能够限制访问资源的线程数,共享锁,应用:限流降级
  22. CountdownLatch与CyclicBarrier:两者都能等待其他线程再继续执行。前者只能一次性使用,后者能重复使用;前者强调一个线程等待其他多个线程,后者强调多个线程间相互等待。
  23. CAS:比较并交换,原子操作(操作系统层面,多线程不能对同一内存区域进行操作),通过查看变量的内存地址上的值,与原值作比较,相同即可修改值。存在ABA问题,加版本号;只能保证一个变量的原子性,多个就要用Synchronized与ReentrantLock、AutomicReference
  24. wait()、notify()、notifyAll():三者都能释放当前线程拥有的锁,前提必须当前线程拥有锁,所以三者都必须写在同步代码中;wait()强调的是等待,等待某共享变量发生变化后再继续执行,后两者强调通知,某共享变量发生变化后去通知其他线程。三者都是跟锁有关的操作,锁是对象级锁,所以都是在Object定义的方法。
  25. 线程池核心参数:核心线程数、最大线程数、空闲等待时间、阻塞队列、拒绝策略
  26. 避免死锁:保证一定的顺序去获取锁;设置等待获取锁的时间,避免线程一直堵塞
  27. 保证多个线程顺序执行,用Thread类的join方法
  28. LongAdder:是AtomicLong的优化版,为了提高吞吐量,用空间换时间思维,高并发竞争大性能会更好,sum结果只是接近值最终一致性。内部维护一个值base,没有竞争时修改base,额外添加一数组用于冲突时存储数值,将base和数组的值累加即是最新结果。
  29. 线程池异常处理,无法感知任务出现异常,要trycatch捕获或者
  30. ForkJoinPool:分而治之,大任务拆分多个子任务,空闲线程从线程的任务队列中窃取任务执行,任务可拆分,任务可窃取。应用在计算型任务。ForkJoinPool可接收执行ForkJoinTask、Runnable、Callable。ForkJoinTask的fork()提交任务,ForkJoinTask的join()获取任务结果,阻塞当前线程等待子任务执行结束返回结果。示例计算数组中一亿个数的总和。
  31. 阻塞队列BlockQueue:执行方法:入队:add(抛异常)、offer(true、false)、put(阻塞);出队:remove(抛异常)、poll(空返回null)、take(阻塞);获取队首元素:element(抛异常)、peek(空返回null)
  32. 阻塞队列,任何时刻,只能有一个线程操作入队put或出队take。基于这个特性,所以put或take操作方法就加ReentrantLock锁。但是阻塞队列为有界时,所以就造成阻塞队列的出入队操作实现瞬间复杂,有两个条件对象,notEmpty和notFull。
    1. 大概思路:当入队时,队列满了,触发条件notFull.await(),所以不能再加入元素,所以持有该锁的线程要主动释放锁。主动释放锁大体流程是,先创建成新的节点,节点的waitStatus是-2(CONDITION),组成条件等待队列,然后释放锁(复用ReentrantLock的unlock底层代码),如果下个获取到锁的线程仍然触发条件notFull.await(),就仍进行上面操作(放入条件等待队列,主动释放锁)。如果没触发是线程执行出队成功,则在出队操作dequeue()去调用notFull.signal(),signal()大概就去将从头到尾遍历条件等待队列,节点转换成waitStatus=-1(SIGNAL)节点,就放入到CLH队列。出队时亦是相同。总结条件等待队列特点:节点的waitStatus是-2(CONDITION),不能去获取锁的,然后触发.signal()时,所有节点转换成CLH队列的节点,所以节点要么全是出队的,要么全是入队的。
  33. 阻塞队列ArrayBlockingQueue:基于数组实现的有界阻塞队列,先进先出,指定容量大小不可扩容,入队和出队共用一把ReentrantLock锁,存取互斥
  34. 阻塞队列LinkedBlockingQueue:基于链表实现的理论上无界的阻塞队列,先进先出,可以指定容量大小,入队和出队是用两把锁,存取不互斥,这也是为什么线程池用LinkedBlockingQueue而不用ArrayBlockingQueue
  35. CopyOnWriteArrayList:并发容器,允许并发对容器写入,写入时将对创建副本,使得同时能读取原数据,适用于读多写少场景,会占用过多内存导致gc,不能实时读。
  36.  ThreadLocal:threadlocal value为什么不是弱引用? - 知乎 (zhihu.com)

    1. ThreadLocal是什么?项目中用到过吗?SimpleDateFormatDemo线程不安全、多数据源连接
    2. ThreadLocal的结构是怎么样的?
    3. 使用ThreadLocal需要注意哪些问题?用static,否则用普通变量的话,在其他处地方要先实例化新的threadLocal引用,导致get不到
    4. 为什么key要设置成弱引用呢?若是强引用,threadLocal引用置为null,则会导致key(threadLocal对象内存泄露),弱引用是gc会回收对象,并且对ThreadLocalMap操作get/set/remove或者扩容都会把key为null的entry清空,所以ThreadLocal不太会发生内存泄漏,规范做法是用完后remove。
    5. 那为什么value不设置成弱引用呢?ThreadLocalMap不是持有对这个value的强引用,它还会被回收吗?若value是弱引用,则GC会回收对象,导致get到空
    6. ThreadLocalMap的hash冲突与扩容:hash冲突则往后遍历放在空值上,扩容扩大原来的2倍,重新hash。
    7. threadLocalMap的key为null的两种清理方式,探测清理和启发清理,在get或set方法可能会附带条件触发,并不能保障一定清理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/534616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity的URP下使用SRPBatcher

大家好,我是阿赵。这里继续来讲一下URP相关的东西。 这次主要说的是SRP Batcher的使用 一、在URP下实现SRP Batcher 1、设置 在我们创建的URPAsset文件的高级选项里面,有一个SRP Batcher的开关,默认就是勾上的。 2、修改shader 在把项目转…

小白白也能学会的 PyQt 教程 —— 自定义组件 Switch Button

文章目录 前言思路讲解代码部分 前言 最近在搞 Python 课程设计,想要搞一个好看的 UI,惊艳全班所有人。但打开 Qt Creator,Win7 风格的复古的按钮是在让我难以下手。 其次,我因为想要打造一个 Fluent UI 样式的设置页面&#xff…

详解c++STL—string组件

目录 一、string基本概念 1、本质 2、string和char * 区别: 3、特点: 二、string构造函数 1、构造函数原型 2、示例 三、string赋值操作 1、赋值的函数原型 2、示例 四、string字符串拼接 1、函数原型 2、示例 五、string查找和替换 1、功…

tomcat目录结构

tomcat服务器安装根目录下有很多子目录,这些目录的作用是: (1)bin:存放了tomcat服务器中的可执行的批处理文件(startup.bat shutdown.bat) (2)conf:存放了tomcat相关的配置文件(其中的server.xml是tomcat服务器核心配置文件) …

26. Pandas处理分析网站原始访问日志

Pandas处理分析网站原始访问日志 目标:真实项目的实战,探索Pandas的数据处理与分析 实例: 数据来源:我自己的wordpress博客蚂蚁学Python – 你有没有为写代码拼过命?那你知不知道 人生苦短,我用Python&am…

Python挑选出无Labelme标注文件的图片文件

Python挑选出无Labelme标注文件的图片文件 前言前提条件相关介绍实验环境Python挑选出无Labelme标注文件的图片文件代码实现输出结果 前言 本文是个人使用Python处理文件的电子笔记,由于水平有限,难免出现错漏,敬请批评改正。 (https://blog.…

【设计原则与思想:总结课】38 | 总结回顾面向对象、设计原则、编程规范、重构技巧等知识点

到今天为止,设计原则和思想已经全部讲完了,其中包括:面向对象、设计原则、规范与重构三个模块的内容。除此之外,我们还学习了贯穿整个专栏的代码质量评判标准。专栏的进度已经接近一半,马上就要进入设计模式内容的学习…

Python: 生成ubuntu apt镜像地址

文章目录 1. 目的2. 设计3. 实现4. 调用5. 参考 1. 目的 每次新配置 Ubuntu 系统,免不了配置 apt 源。尽管可以通过 GUI 界面进行选择,但自动化程度不够,不同桌面(Unity/Gnome/KDE)下的界面也不太一样; 使…

Java基础-sleep和wait的区别

本文介绍Java中sleep和wait方法的使用区别 文章目录 sleep()wait()sleep()和wait()对比区别相同点 sleep() 查看sleep方法,可见其是static native方法 public static native void sleep(long millis) throws InterruptedException;sleep()方法需要指定等待的时间。…

HTTP第14讲——HTTP传输大文件的方法

背景 HTTP 可以传输很多种类的数据,不仅是文本,也能传输图片、音频和视频。 早期互联网上传输的基本上都是只有几 K 大小的文本和小图片,现在的情况则大有不同。网页里包含的信息实在是太多了,随随便便一个主页 HTML 就有可能上百…

java常用集合

java集合又是一个新世界了,从前在我刚接触java的时候,一直在纠结 集合这东西到底有啥用,后来代码写的多了。才开始学习集合 集合也叫容器。顾名思意 就是存放对象的器皿。 主要是由两大接口派生而来 :一个是 Collecton接口&#…

LeetCode高频算法刷题记录2

文章目录 1. 最大子数组和【简单】1.1 题目描述1.2 解题思路1.3 代码实现 2. 合并两个有序链表【简单】2.1 题目描述2.2 解题思路2.3 代码实现 3. 两数之和【简单】3.1 题目描述3.2 解题思路3.3 代码实现 4. 二叉树的层序遍历【中等】4.1 题目描述4.2 解题思路4.3 代码实现 5. …

代码随想录算法训练营第四十二天 | 背包问题

背包问题 理论 基础:二维 文档讲解:代码随想录 (programmercarl.com) 视频讲解:带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩…

Revit SDK:ErrorHandling

前言 本文介绍 Revit 的错误处理机制。 内容 程序员对错误处理的定义和理解 程序的错误处理机制可以分为两种类型:错误返回码和异常捕捉。 错误返回码是指在程序中遇到错误时,通过函数返回值来表明错误的类型和信息。错误返回码可以在程序中被预测和…

MySQL数据落盘原理(data page、redo log、undo log、binlog、xa-2pc等源码分析)

文章目录 前言一、Innodb如何作为MySQL插件的二、page cleaner thread三、Update操作源码梳理1、生成undo log2、更新数据3、生成redo log 四、MTR与将脏页添加到Flush List1、MTR2、脏页添加到Flush List 五、事务提交1、xa-prepare2、xa-commit2.1、process_flush_stage_queu…

概率统计与计算机技术的联系及在生活当中的应用研究

title: 概率统计与计算机技术的联系及在生活当中的应用研究 date: 2023-05-16 11:42:26 tags: 题目:概率统计与计算机技术的联系及在生活当中的应用研究 摘 要 概率论与数理统计是研究随机现象统计规律性的一门学科,是理工科各专业的一门重要的基础课程…

shell免交互

shell免交互 Here Document 免交互 使用I/O重定向的方式将命令列表提供给交互式程序或命令,比如 ftp、cat 或 read 命令。 是标准输入的一种替代品可以帮助脚本开发人员不必使用临时文件来构建输入信息,而是直接就地生产出一个“文件”并用作“命令”的…

Python 爬虫(四):Selenium 框架

Selenium 是一个用于测试 Web 应用程序的框架,该框架测试直接在浏览器中运行,就像真实用户操作一样。它支持多种平台:Windows、Linux、Mac,支持多种语言:Python、Perl、PHP、C# 等,支持多种浏览器&#xff…

Android中的IPC方式

Android中的IPC方式 1.Bundle 其中Intent就是用Bundle进行传播 四大组件间的进程间通信 2.使用文件共享 2.1文件共享的缺点 无并发,适用于交换简单的数据实时性不高的情景 使用文件共享容易出: 内容不一致:如果多个线程同时写入文件&…

【JavaWeb】-- Request和Response、JSP、会话技术

文章目录 Request和Response1.概述2.Request对象2.1 Request继承体系2.2Request获取请求数据2.3 IDEA创建Servlet2.4 请求参数中文乱码问题POST请求解决方案GET请求解决方案 2.5 Request请求转发 3.Response对象3.1 Response设置响应数据功能介绍3.2 Response请求重定向3.3 路径…