目录

  • 一、进程与线程
  • 二、线程组与线程池
    • 1、线程组
    • 2、线程组和线程池有啥区别?
  • 三、用户线程与守护线程
  • 四、并行与并发
  • 五、悲观锁与乐观锁
    • 1、悲观锁
    • 2、乐观锁
  • 六、CAS
    • 1、什么是CAS?
    • 2、CAS带来的问题
  • 七、那些年学过的锁
    • 1、公平锁与非公平锁
    • 2、独占锁与共享锁
    • 3、可重入锁与不可重入锁
  • 八、死锁、活锁、饿死
    • 1、死锁
    • 2、产生死锁的4个必要条件
    • 3、饥饿
    • 4、产生饥饿的主要原因
    • 5、如何避免饥饿
    • 6、活锁
    • 7、如何避免活锁
  • 九、多线程锁的升级原理是什么?
    • 1、无锁
    • 2、偏向锁
    • 3、轻量级锁
    • 4、重量级锁
    • 5、锁状态对比
    • 6、锁消除
  • 十、Java多线程思维导图

一、进程与线程

程序本身是静态的,是众多代码的组合产物,代码保存在文件中。如果程序要运行,则需要将程序加载到内存中,通过编译器将其编译成计算机能够理解的方式运行。
如果想启动一个Java程序,先要创建一个JVM进程。
进程是操作系统进行资源分配的最小单位,在一个进程中可以创建多个线程。多个线程各自拥有独立的局部变量、线程堆栈和程序计数器,能够访问共享的资源。

  1. 进程是操作系统分配资源的最小单位,线程是CPU调度的最小单位;
  2. 一个进程中可以包含多个线程;
  3. 进程与进程之间是相对独立的,进程中的线程之间并不完全独立,可以共享进程中的堆内存、方法区内存、系统资源等;
  4. 进程上下文的切换要比线程的上下文切换慢很多;
  5. 某个进程发生异常,不会对其它进程造成影响,但,某个线程发生异常,可能会对此进程中的其它线程造成影响;

二、线程组与线程池

1、线程组

线程组可以管理多个线程,顾名思义,线程组,就是把功能相似的线程放到一个组里,方便管理。

package com.guor.test;public class ThreadGroupTest {public static void main(String[] args) {// 创建线程组ThreadGroup threadGroup = new ThreadGroup("nezha");Thread thread = new Thread(threadGroup,()->{// 线程组名称String groupName = Thread.currentThread().getThreadGroup().getName();// 线程名称String threadName = Thread.currentThread().getName();System.out.println("groupName -- "+groupName);//groupName -- nezhaSystem.out.println("threadName -- "+threadName);//threadName -- thread},"thread");thread.start();}
}

2、线程组和线程池有啥区别?

  1. 线程组中的线程可以跨线程修改数据,而线程组和线程组之间不可以跨线程修改数据;
  2. 线程池就是创建一定数量的线程,批量处理任务,当前任务执行完毕后,线程又可以去执行其它任务,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
  3. 线程池可以有效的管理线程的数量,避免线程的无限制创建,线程是很耗费系统资源的,动不动就会产生OOM,并且会造成cpu过度切换,也有强大的拓展功能,比如延时定时线程池。

三、用户线程与守护线程

在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 。

用户线程是最常见的线程,比如通过main方法启动,就会创建一个用户线程。

Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。

JVM中的垃圾回收、JIT编译器线程就是最常见的守护线程。

只要有一个用户线程在运行,守护线程就会一直运行。只有所有的用户线程都结束的时候,守护线程才会退出。

编写代码时,也可以通过thread.setDaemon(true)指定线程为守护线程。

Thread daemonTread = new Thread();// 设定 daemonThread 为 守护线程,默认falsedaemonThread.setDaemon(true);// 验证当前线程是否为守护线程,返回 true 则为守护线程daemonThread.isDaemon();

守护线程的注意事项:

  1. thread.setDaemon(true)要在thread.start()之前设置,否则会抛出IllegalThreadStateException异常。你不能把正在运行的线程设置为守护线程;
  2. 在守护线程中产生的新线程也是守护线程;
  3. 读写操作或者计算逻辑不可以设置为守护线程;

四、并行与并发

并行指当多核CPU中的一个CPU执行一个线程时,其它CPU能够同时执行另一个线程,两个线程之间不会抢占CPU资源,可以同时运行。

并发指在一段时间内CPU处理多个线程,这些线程会抢占CPU资源,CPU资源根据时间片周期在多个线程之间来回切换,多个线程在一段时间内同时运行,而在同一时刻不是同时运行的。

并行和并发的区别?

  1. 并行指多个线程在一段时间的每个时刻都同时运行,并发指多个线程在一段时间内同时运行(不是同一时刻,一段时间内交叉执行)
  2. 并行的多个线程不会抢占系统资源,并发的多个线程会抢占系统资源;
  3. 并行是多CPU的产物,单核CPU中只有并发,没有并行;

五、悲观锁与乐观锁

1、悲观锁

悲观锁在一个线程进行加锁操作后使得该对象变为该线程的独有对象,其它的线程都会被悲观锁阻拦在外,无法操作。

悲观锁的缺陷:

  1. 一个线程获得悲观锁后其它线程必须阻塞。
  2. 线程切换时要不停的释放锁和获取锁,开销巨大。
  3. 当一个低优先级的线程获得悲观锁后,高优先级的线程必须等待,导致线程优先级倒置,synchronized锁是一种典型的悲观锁。

2、乐观锁

乐观锁认为对一个对象的操作不会引发冲突,所以每次操作都不进行加锁,只是在最后提交更改时验证是否发生冲突,如果冲突则再试一遍直到成功为止,这个尝试的过程被称为自旋。乐观锁其实并没有加锁,但乐观锁也引入了诸如ABA、自旋次数过多等问题。

乐观锁一般会采用版本号机制,先读取数据的版本号,在写数据时比较版本号是否一致,如果一致,则更新数据,否则再次读取版本号,直到版本号一致。

Java中的乐观锁都是基于CAS自旋实现的。

六、CAS

1、什么是CAS?

Compare And Swap。

CAS(V, A, B) ,内存值V,期待值A, 修改值B(V 是否等于 A, 等于执行, 不等于将B赋给V)

2、CAS带来的问题

(1)ABA问题

CAS操作的流程为:

  1. 读取原值。
  2. 通过原子操作比较和替换。
  3. 虽然比较和替换是原子性的,但是读取原值和比较替换这两步不是原子性的,期间原值可能被其它线程修改。

ABA问题有些时候对系统不会产生问题,但是有些时候却也是致命的。

ABA问题的解决方法是对该变量增加一个版本号,每次修改都会更新其版本号。JUC包中提供了一个类AtomicStampedReference,这个类中维护了一个版本号,每次对值的修改都会改动版本号。

(2)自旋次数过多

CAS操作在不成功时会重新读取内存值并自旋尝试,当系统的并发量非常高时即每次读取新值之后该值又被改动,导致CAS操作失败并不断的自旋重试,此时使用CAS并不能提高效率,反而会因为自旋次数过多还不如直接加锁进行操作的效率高。

(3)只能保证一个变量的原子性

当对一个变量操作时,CAS可以保证原子性,但同时操作多个变量时CAS就无能为力了。

可以封装成对象,再对对象进行CAS操作,或者直接加锁。

七、那些年学过的锁

1、公平锁与非公平锁

  • 公平锁:按照线程在队列中的排队顺序,先到者先拿到锁
  • 非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的

2、独占锁与共享锁

  • 独占锁:当多个线程则争抢锁的过程中,无论是读操作还是写操作,只能有一个线程获取到锁,其他线程阻塞等待。
  • 共享锁:允许多个线程同时获取共享资源,采取的是乐观锁的机制,共享锁限制写写操作、读写操作,但不会限制读读操作。

3、可重入锁与不可重入锁

  • 可重入锁:一个线程可以多次占用同一个锁,但是解锁时,需要执行相同次数的解锁操作;
  • 不可重入锁:一个线程不能多次占用同一个锁;

八、死锁、活锁、饿死

1、死锁

多个线程互相持有对方需要的资源,导致多个线程相互等待,无法继续执行后续任务。

2、产生死锁的4个必要条件

  1. 互斥条件:指进程对所分配到的资源进行排它性使用,在一段时间内某资源只由一个进程占用,如果此时还有其他进程请求资源,则请求者只能等待,直至占有资源的进程被释放;
  2. 请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
  3. 不可剥夺:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
  4. 循环等待:一个等待一个,产生了一个闭环。

3、饥饿

饥饿指的是线程由于无法获取需要的资源而无法继续执行。

4、产生饥饿的主要原因

  1. 高优先级的线程不断抢占资源,低优先级的线程抢不到;
  2. 某个线程一直不释放资源,导致其他线程无法获取资源;

5、如何避免饥饿

  1. 使用公平锁分配资源;
  2. 为程序分配足够的系统资源;
  3. 避免持有锁的线程长时间占用锁;

6、活锁

活锁指的是多个线程同时抢占同一个资源时,都主动将资源让给其他线程使用,导致这个资源在多个线程之间来回切换,导致线程因无法获取相应资源而无法继续执行的现象。

7、如何避免活锁

可以让多个线程随机等待一段时间后再次抢占资源,这样会大大减少线程抢占资源的冲突次数,有效避免活锁的产生。

九、多线程锁的升级原理是什么?

锁的状态总共有四种,无锁状态、偏向锁、轻量级锁、重量级锁。

随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级到重量级锁。但是锁的升级是单向的,只能升级不能降级。

1、无锁

没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功,其它修改失败的线程会不断重试直到修改成功。

无锁总是假设对共享资源的访问没有冲突,线程可以不停执行,无需加锁,无需等待,一旦发现冲突,无锁策略则采用一种称为CAS的技术来保证线程执行的安全性,CAS是无锁技术的关键。

2、偏向锁

对象的代码一直被同一线程执行,不存在多个线程竞争,该线程在后续执行中自动获取锁,降低获取锁带来的性能开销。偏向锁,指的是偏向第一个加锁线程,该线程是不会主动释放偏向锁的,只有当其他线程尝试竞争偏向锁才会被释放。

偏向锁的撤销,需要在某个时间点上没有字节码正在执行时,先暂停偏向锁的线程,然后判断锁对象是否处于被锁定状态,如果线程不处于活动状态,则将对象头设置成无锁状态,并撤销偏向锁。

如果线程处于活动状态,升级为轻量级锁的状态

3、轻量级锁

轻量级锁是指当锁是偏向锁的时候,被第二个线程B访问,此时偏向锁就会升级为轻量级锁,线程B会通过自旋的形式尝试获取锁,线程不会阻塞,从er提升性能。

当前只有一个等待线程,则该线程将通过自旋进行等待。但是当自旋超过一定次数时,轻量级锁便会升级为重量级锁,当一个线程已持有锁,另一个线程在自旋,而此时第三个线程来访时,轻量级锁也会升级为重量级锁。

注:自旋是什么?

自旋(spinlock)是指当一个线程获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

4、重量级锁

指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。

重量级锁通过对象内部的监听器(monitor)实现,而其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。

5、锁状态对比

偏向锁 轻量级锁 重量级锁
使用场景 只有一个线程进入同步块 虽然很多线程,但没有冲突,线程进入时间错开因而并未争抢锁 发生了锁争抢的情况,多条线程进入同步块争用锁
本质 取消同步操作 CAS操作代替互斥同步 互斥同步
优点 不阻塞,执行效率高(只有第一次获取偏向锁时需要CAS操作,后面只是比对ThreadId) 不会阻塞 不会空耗CPU
缺点 适用场景太局限。若竞争产生,会有额外的偏向锁撤销的消耗 长时间获取不到锁空耗CPU 阻塞,上下文切换,重量级操作,消耗操作系统资源

6、锁消除

消除锁是虚拟机另外一种锁的优化,这种优化更彻底,Java虚拟机在JIT编译时(可以简单理解为当某段代码即将第一次被执行时进行编译,又称即时编译),通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过这种方式消除没有必要的锁,可以节省毫无意义的请求锁时间,如StringBuffer的append是一个同步方法,但是在add方法中的StringBuffer属于一个局部变量,别切不会被其它线程所使用,因此StringBuffer不可能存在共享资源竞争的情景,JVM会自动将其锁消除。

十、Java多线程思维导图

哪吒精品系列文章:

Java学习路线总结,搬砖工逆袭Java架构师

10万字208道Java经典面试题总结(附答案)

SQL性能优化的21个小技巧

Java基础教程系列

Spring Boot 进阶实战

Java高并发编程实战1,那些年学过的锁相关推荐

  1. Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...

    JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...

  2. 29W 字总结阿里 Java 高并发编程:案例 + 源码 + 面试 + 系统架构设计

    下半年的跳槽季已经开始,好多同学已经拿到了不错的 Offer,同时还有一些同学对于 Java 高并发编程还缺少一些深入的理解,不过不用慌,今天老师分享的这份 27W 字的阿里巴巴 Java 高并发编程 ...

  3. Java 7并发编程实战手册

    2019独角兽企业重金招聘Python工程师标准>>> Java 7并发编程实战手册 本书是 Java 7 并发编程的实战指南,介绍了Java 7 并发API 中大部分重要而有用的机 ...

  4. Java高并发编程详解系列-Java线程入门

    根据自己学的知识加上从各个网站上收集的资料分享一下关于java高并发编程的知识点.对于代码示例会以Maven工程的形式分享到个人的GitHub上面.   首先介绍一下这个系列的东西是什么,这个系列自己 ...

  5. java 并发集合_《Java 7并发编程实战手册》第六章并发集合

    由人民邮电出版社出版的<Java 7并发编程实战手册>终于出版了,译者是俞黎敏和申绍勇,该书将于近期上架.之前并发编程网组织翻译过此书,由于邮电出版社在并发网联系他们之前就找到了译者,所以 ...

  6. Java高并发编程 (马士兵老师视频)笔记(一)同步器

    本篇主要总结同步器的相关例子:包括synchronized.volatile.原子变量类(AtomicXxx).CountDownLatch.ReentrantLock和ThreadLocal.还涉及 ...

  7. Java高并发编程学习(三)java.util.concurrent包

    简介 我们已经学习了形成Java并发程序设计基础的底层构建块,但对于实际编程来说,应该尽可能远离底层结构.使用由并发处理的专业人士实现的较高层次的结构要方便得多.要安全得多.例如,对于许多线程问题,可 ...

  8. Java 高并发第二阶段实战---高并发设计模式,内存模型,CPU一致性协议,volatile关键字剖析

    第二阶段的课程主要围绕着Volatile关键字,内存重排序,Happen-Before,Cpu一致性协议,高并发下的设计模式以及类加载器几个大的方面展开,下面是内容详细信息,本教程是本人录制,下载地址 ...

  9. @冰河老师的巨作,人手一册的Java高并发编程指南,值得了解一下

    还真不好意思,这次 Java Thread Pool 惊爆了! 高并发是每一个后端开发工程师都头疼的问题,也是工程师能力的分水岭.要想基于JDK核心技术,玩转高并发编程,必须要好好修炼内功才行. 文章 ...

  10. Java高并发编程:活跃性危险

    Java高并发程序中,不得不出现资源竞争以及一些其他严重的问题,比如死锁.线程饥饿.响应性问题和活锁问题.在安全性与活跃性之间通常存在依赖,我们使用加锁机制来确保线程安全,但是如果过度地使用加锁,则可 ...

最新文章

  1. mybatis mapper.xml dtd_全栈开发踩坑之路4-用MyBatis实现服务
  2. samtools merge_【生信工具】Samtools 安装与使用 | “十年以后,工具难免沦为朋友”...
  3. BZOJ 4555 [Tjoi2016Heoi2016]求和
  4. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1078:求分数序列和
  5. 显示三维图片序列_SLAM结合三维检测
  6. Vue学习之监视属性watch
  7. 1026. 节点与其祖先之间的最大差值
  8. itextpdf html 样式,将HTML解析为PDF的iText样式
  9. jvm 的内存分配方式
  10. 2008新建域时失败问题
  11. 【转】Latex入门教程
  12. FileZilla工具FTP乱码问题修改
  13. 浅谈Android自定义View
  14. zoj题目分类详细的
  15. 中国计算机展望未来,作文:展望未来中国的2025
  16. 正确的序号及标点使用格式(参考文)
  17. 计算机学院举办 温暖冬日 感恩社会 活动,E·活动 | 我院举办“温暖冬日,感恩社会”活动...
  18. Javascript中LenB的计算(ASP)
  19. Android Studio 往虚拟机添加音乐
  20. 小木虫网站无法登陆(账号突然被封禁)的解决办法

热门文章

  1. 易语言易语言浏览器html5,易语言创建的浏览器源码
  2. pip install numpy 安装numpy失败
  3. Lint 静态代码检查工具
  4. 非华为电脑安装华为电脑管家
  5. win10或11非华为电脑安装最新的电脑管家(支持移动应用引擎)安装方法及问题解决
  6. JavaScript使用Modbus协议实现RTU设备连云
  7. linux配置网桥,Linux下通过brctl配置网桥
  8. 从硬件到软件玩转Nordic nRF52840 低功耗蓝牙
  9. 根据开始日期,结束日期,计算出日历上有几周的方法
  10. 2016版excel_【收藏转发】全套Excel自动计算表139份(回弹、土工、钢筋、集料、粉煤灰等)...