java八股复习指南-多线程篇

news/2024/11/15 13:29:43/文章来源:https://www.cnblogs.com/forest-pan/p/18307188

多线程

线程的实现

在 Java 中,实现多线程的主要有以下四种

  1. 继承 Thread 类,重写 run() 方法;
  2. 实现 Runnable 接口,实现 run() 方法,并将 Runnable 实现类的实例作为 Thread 构造函数的参数 target;
  3. 实现 Callable 接口,实现 call() 方法,然后通过 FutureTask 包装器来创建 Thread 线程;
  4. 通过 ThreadPoolExecutor 创建线程池,并从线程池中获取线程用于执行任务;

不使用Executors创建,而是用ThreadPoolExecutor创建

通过工厂模式,将创建产品实例的权利移交工厂,我们不再通过new来创建我们所需的对象,而是通过工厂来获取我们需要的产品。降低了产品使用者与使用者之间的耦合关系;创建线程池没有显式new,而是通过Executors这个静态方法newCaChedThreadPool来完成的;


Thread类与Runnable接口比较:

实现一个自定义的线程类,可以有继承Thread类或者实现Runnable接口的方式,由于java单继承、多实现的特性,Runnable接口使用比Thread更加灵活

Callable接口:

通常来说,我们使用RunnableThread来创建一个新的线程。但是它们有一个弊端,就是run方法是没有返回值的。而有时候我们希望开启一个线程去执行一个任务,并且这个任务执行完成后有一个返回值

JDK提供了Callable接口与Future类为我们解决这个问题,这也是所谓的“异步”模型。

线程的六种状态:

// Thread.State 源码
public enum State {NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
}
  1. NEW:
  • 不能反复调用同一个线程的start()方法
  • 处于TERMINATED状态的线程不能再次调用start()方法
  1. RUNNABLE:

运行状态。处于RUNNABLE状态的线程在Java虚拟机中运行,也有可能在等待其他系统资源(比如I/O)。

  1. BLOCKED:

阻塞状态。处于BLOCKED状态的线程正等待锁的释放以进入同步区。

  1. WAITING

等待状态。处于等待状态的线程变成RUNNABLE状态需要其他线程唤醒。

以下方法使进程进入等待状态:

  1. TIMED_WAITING

超时等待状态。线程等待一个具体的时间,时间到后会被自动唤醒。

  1. TERMINATED

终止状态。此时线程已执行完毕。

转换成TERMINATED状态的三种方法:

  • Object.wait()
  • Thread.join()
  • LockSupport.park()

Java线程间的通信:

锁与同步

在Java中,锁的概念都是基于对象的,所以我们又经常称它为对象锁。线程和锁的关系,我们可以用婚姻关系来理解。一个锁同一时间只能被一个线程持有。也就是说,一个锁如果和一个线程“结婚”(持有),那其他线程如果需要得到这个锁,就得等这个线程和这个锁“离婚”(释放)。

等待/通知机制

Java多线程的等待/通知机制是基于Object类的wait()方法和notify(), notifyAll()方法来实现的。

信号量

使用volitile关键字实现信号量。volitile关键字能够保证内存的可见性,如果用volitile关键字声明了一个变量,在一个线程里面改变了这个变量的值,那其它线程是立马可见更改后的值的。

其他通信相关

join方法

join()方法是Thread类的一个实例方法。它的作用是让当前线程陷入“等待”状态,等join的这个线程执行完成后,再继续执行当前线程。

sleep方法

sleep方法是Thread类的一个静态方法。它的作用是让当前线程睡眠一段时间。

wait方法与sleep方法的区别:

sleep仅仅释放cpu资源,不会释放锁,所以易死锁。而wait方法会释放cpu资源,也会释放当前锁。

原理篇

volatitle

valatitle 保证内存可见性且禁止重排序

synchronized与锁

四种状态:无锁、偏向锁、轻量级锁、重量级锁

无锁->偏向锁->轻量级锁->重量级锁

  • 偏向锁:

顾名思义,它会偏向于第一个访问锁的线程,如果在接下来的运行过程中,该锁没有被其他的线程访问,则持有偏向锁的线程将永远不需要触发同步。
如果在运行过程中,遇到了其他线程抢占锁,则持有偏向锁的线程会被挂起,JVM会尝试消除它身上的偏向锁,将锁恢复到标准的轻量级锁。

  • 轻量级锁:

是指当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。

若当前只有一个等待线程,则该线程通过自旋进行等待。但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁。

  • 重量级锁:

在轻量级锁状态下,如果有第三个来访时,就会自动升级成重量级锁

优点 缺点 适用场景
偏向锁 加锁和解锁不需要额外的消耗,和执行非同步方法比仅存在纳秒级的差距。 如果线程间存在锁竞争,会带来额外的锁撤销的消耗。 适用于只有一个线程访问同步块场景。
轻量级锁 竞争的线程不会阻塞,提高了程序的响应速度。 如果始终得不到锁竞争的线程使用自旋会消耗CPU。 追求响应时间。同步块执行速度非常快。
重量级锁 线程竞争不使用自旋,不会消耗CPU。 线程阻塞,响应时间缓慢。 追求吞吐量。同步块执行速度较长。

cas与原子操作

乐观锁与悲观锁

悲观锁:

它总是认为每次访问共享资源时会发生冲突,所以必须对每次数据操作加上锁,以保证临界区的程序同一时间只能有一个线程在执行。

乐观锁:

乐观锁总是假设对共享资源的访问没有冲突,线程可以不停地执行,无需加锁也无需等待。而一旦多个线程发生冲突,乐观锁通常是使用一种称为CAS的技术来保证线程执行的安全性。乐观锁天生免疫死锁

乐观锁多用于“读多写少“的环境,避免频繁加锁影响性能;而悲观锁多用于”写多读少“的环境,避免频繁失败和重试影响性能。

CAS

如果有一个多个线程共享的变量i原本等于5,我现在在线程A中,想把它设置为新的值6;

CAS的全称是:比较并交换(Compare And Swap)。在CAS中,有这样三个值:

  • V:要更新的变量(var),指代变量(i)
  • E:预期值(expected),指旧值(5)
  • N:新值(new),指要设置的值(6)

比较并交换的过程如下:

判断V是否等于E,如果等于,将V的值设置为N;如果不等,说明已经有其它线程更新了V,则当前线程放弃更新,什么都不做。

线程池原理

主要的任务处理流程:

如何做到线程复用

ThreadPoolExecutor在创建线程时,会将线程封装成工作线程worker,并放入工作线程组中,然后这个worker反复从阻塞队列中拿任务去执行。

首先去执行创建这个worker时就有的任务,当执行完这个任务后,worker的生命周期并没有结束,在while循环中,worker会不断地调用getTask方法从阻塞队列中获取任务然后调用task.run()执行任务,从而达到复用线程的目的。只要getTask方法不返回null,此线程就不会退出。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

W外链创建抖音私信卡片教程,私信卡片跳转微信工具

W外链地址wai.cn 在数字化时代的浪潮中,私域流量的价值愈发凸显,成为企业获取用户、建立品牌忠诚度、提升转化率的关键手段。抖音,作为当下最热门的短视频社交平台之一,其用户基数庞大、互动性强,为企业私域引流提供了绝佳的舞台。而抖音私信卡片,正是私域引流中的一把利…

Gradle更换阿里云镜像源

1、下载Gradle 官网:https://gradle.org/releases/ 2、配置Gradle环境变量 3、安装目录下找到init.d文件夹 再该文件夹中创建init.gradle文件,编写一下脚本替换阿里云镜像// 阿里云仓库和源仓库地址对比:https://developer.aliyun.com/mvn/guidegradle.projectsLoaded {root…

CANXL协议解读系列 | (2)一文读懂ISO 11898-2:2024 CANXL物理层

伴随着ISO 11898-2:2024版本的更新,第三代CAN总线通信CAN XL技术迎来了它的序幕。 2024年3月22日, ISO 推出11898-2:2024版本,标志着CAN总线收发器的最高速率由CANFD行业认可的8Mbit/s提速到最高20Mbit/s(2024年5月24日ISO 11898-1 2024已发表)。20Mbit/s的传输带…

EFCore -CodeFirst模式 数据库使用SqLite

首先安装nuget包:System.Data.SQLite 和 SQLite.CodeFirst,如下二图:然后在App.config中配置数据库连接字符串: <connectionStrings><add name="StuDB" connectionString="data source=BoilerCalculator.db" providerName="System.Data.S…

log4net 在.NET Core 控制台程序中的应用(2)

简介 本文主要讲解log4net 在.NET Core控制台程序中的应用 步骤 1.安装log4net Nuget包 2.增加配置文件 3.直接调用 4.验证结果 实施 1.安装log4net Nuget包 首先,需要在你的.NET Core项目中安装log4net包。可以通过NuGet包管理器来安装。打开你的项目,然后使用以下命令安装l…

.NET开源、简单、实用的数据库文档生成工具

前言 今天大姚给大家分享一款.NET开源(MIT License)、免费、简单、实用的数据库文档(字典)生成工具,该工具支持CHM、Word、Excel、PDF、Html、XML、Markdown等多文档格式的导出:DBCHM。 支持的数据库 SqlServer、MySQL、Oracle、PostgreSQL、DB2、SQLite。 文档的内容都包…

记4道弱智题

今天集训模拟赛,3h,喜提110pts/400pts。 第一题:反复覆盖区间,求各点处的最小值。 上来想了差分,记录左端点等方法,越写越长。20min跳了,慌。 第二题:模拟题,ipv6压缩。 看起来不难,开始写,先去掉全0串,再去掉前导零,最后处理输出,样例全过了,我觉得能A。 第三题…

log4net 在.NET Core 控制台程序中的应用

简介 本文主要讲解log4net 在.NET Core控制台程序中的应用 步骤 1.安装log4net Nuget包 2.增加配置文件 3.增加封装的LogHelper的类 4.调用 5.验证结果 实施 1.安装log4net Nuget包 首先,需要在你的.NET Core项目中安装log4net包。可以通过NuGet包管理器来安装。打开你的项目,…

iOS开发基础116-性能监控

在iOS开发中,性能监控是确保应用流畅运行和用户体验的关键。常用的性能监控工具能够帮助开发者实时监控系统性能,检测和诊断性能问题。下面列举几款常用的iOS性能监控工具,深入解析其底层原理、优缺点。 1. Instruments Instruments 是由Apple官方提供的用于性能分析和调试的…

【转载】浅谈 pb_ds 库及其在OI其他算竞中的应用

笔记 2023年11月16日 35 0 【转载】浅谈 pb_ds 库及其在OI其他算竞中的应用 【原链接】这篇太叼了! pb_ds,比 STL 更强大的模板库。upd. on 10.27 更新了优先队列的常数分析,增加了“万能头文件”的内容。 前言 之前看到过一篇关于 pb_ds 写得很好的文章,但现在找不到了;O…

[BJDCTF2020]Mark loves cat(源码泄露+命令执行)

扫描之后发现是/.git源码泄露 python GitHack.py http://56ad87c1-d8fb-463d-9480-f0fbee5176a0.node5.buuoj.cn:81/.git/ 之后出现源码查看index.php<?php// 包含外部文件 flag.php,可能包含变量 $flag include flag.php;// 初始化三个变量 $yds = "dog"; …

易优CMS根据aid获取文档页面链接

使用sql等标签获取到文档信息,但是没有获取到文档页面的链接,可以使用以下方法生成。 1、在根目录下\extend\function.php中创建方法: if (!function_exists(diy_get_arcurl)) {/*** 获取前台文档的URL* @param integer $aid 文档ID* @param integer $typeid 栏目ID* …