多线程总结(持续更新)

 线程的优点

 进程与线程的区别

创建线程三个方法

结束线程的两个常用方法

 等待一个线程 join()

获取当前线程的引用

Java线程共有⼏种状态?状态之间怎么切换的?

synchronized特点

volatile的特点

 线程不安全问题及解决方案

wait() 和notify() 的作用

wait()和sleep()的对比

常见的锁策略 

synchronized自身优化手段/synchronized实现原理

你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?

介绍下读写锁?

什么是⾃旋锁,为什么要使⽤⾃旋锁策略呢,缺点是什么?

synchronized 是可重⼊锁么?

CAS

总结什么是CAS:

CAS主要解决了以下问题:

CAS内在的ABA问题是什么

为了解决ABA问题,可以采用以下方法:

 

 线程的优点

  1. 创建⼀个新线程的代价要⽐创建⼀个新进程⼩得多
  2. 与进程之间的切换相⽐,线程之间的切换需要操作系统做的⼯作要少很多
  3. 线程占⽤的资源要⽐进程少很多
  4. 能充分利⽤多处理器的可并⾏数量
  5. 在等待慢速I/O操作结束的同时,程序可执⾏其他的计算任务
  6. 计算密集型应⽤,为了能在多处理器系统上运⾏,将计算分解到多个线程中实现
  7. I/O密集型应⽤,为了提⾼性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

 进程与线程的区别

  1. 进程是包含线程的. 每个进程⾄少有⼀个线程存在,即主线程。
  2. 进程和进程之间不共享内存空间. 同⼀个进程的线程之间共享同⼀个内存空间.
  3. 进程是系统分配资源的最⼩单位,线程是系统调度的最⼩单位。

创建线程三个方法

1.继承Thread类,重写run方法

    public static void main(String[] args) {class MyThread extends Thread{@Overridepublic void run() {System.out.println("成功创建线程!");}}MyThread thread = new MyThread();thread.start();}

2.实现Runnable接口,重写run方法

public static void main(String[] args) {class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("成功创建线程!");}}MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable,"继承Runnable接口实现");thread.start();}

3.lambda表达式创建Runnable子类对象(推荐)

public static void main(String[] args) {Thread t1=new Thread(()->{System.out.println("使用匿名内部类成功创建线程!");});thread.start();}

结束线程的两个常用方法

1.使用定义变量作为标志位,需要给标志物加上volatile保证变量的可见性,被修改时可以被看到

public class MyThread extends Thread {private volatile boolean running = true;@Overridepublic void run() {while (running) {// 执行你的任务// ...// 模拟一些工作try {Thread.sleep(100);} catch (InterruptedException e) {// 线程被中断时,可以选择停止运行running = false;}}}public void stopThread() {running = false;}
}

2.使⽤ Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替⾃定义标志位.

Thread 内部包含了⼀个 boolean 类型的变量作为线程是否被中断的标记

public class MyThread extends Thread {@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()) {// 执行你的任务// ...// 模拟一些工作try {Thread.sleep(100);} catch (InterruptedException e) {// 线程被中断时,不处理中断,只是退出循环}}}
}

 等待一个线程 join()

thread.join()让主线程等待thread执行完再执行

public class Thread1 {public static void main(String[] args) throws InterruptedException {// 使用lambda表达式创建一个新线程Thread thread = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("子线程正在执行: " + i);try {Thread.sleep(500); // 模拟耗时操作} catch (InterruptedException e) {// 如果子线程在sleep时被中断,这里只是简单地打印堆栈跟踪e.printStackTrace();// 通常,我们应该在子线程中适当地处理中断}}});// 启动线程thread.start();// 当前线程(主线程)等待子线程执行完毕thread.join();// 子线程执行完毕后,主线程继续执行System.out.println("子线程已经执行完毕,主线程继续执行");}
}

获取当前线程的引用

当你在一个多线程环境中编写代码时,你经常需要知道当前正在执行代码的线程是哪个,这时就可以使用 Thread.currentThread() 来获取当前线程的引用。

public class Thread1 {public static void main(String[] args) {Thread Thread = Thread.Thread();System.out.println("当前线程名称: " + Thread.getName());}
}

Java线程共有⼏种状态?状态之间怎么切换的?

  • NEW: 安排了⼯作, 还未开始⾏动. 新创建的线程, 还没有调⽤ start ⽅法时处在这个状态.
  • RUNNABLE: 可⼯作的. ⼜可以分成正在⼯作中和即将开始⼯作. 调⽤ start ⽅法之后, 并正在 CPU 上 运⾏/在即将准备运⾏ 的状态.
  •  BLOCKED: 使⽤ synchronized 的时候, 如果锁被其他线程占⽤, 就会阻塞等待, 从⽽进⼊该状态.
  •  WAITING: 调⽤ wait ⽅法会进⼊该状态.
  • TIMED_WAITING: 调⽤ sleep ⽅法或者 wait(超时时间) 会进⼊该状态.
  • TERMINATED: ⼯作完成了. 当线程 run ⽅法执⾏完毕后, 会处于这个状态.

synchronized特点

  • 互斥性:当一个线程访问某个被 synchronized 修饰的代码块或方法时,其他线程无法同时访问这个代码块或方法。这种互斥性保证了同一时刻只有一个线程能执行某个代码段,从而避免了数据竞争和脏读等问题。

  • 可重入性:同一个线程可以多次获得同一个对象的锁,即允许一个线程在持有锁的情况下再次进入同步代码块或方法。这避免了死锁和不必要的线程切换开销。

  • 可见性:当一个线程释放锁时,它会将修改后的共享变量的值刷新到主内存中,因此其他线程能够立即看到这些修改后的值。这保证了线程之间对共享变量的可见性。

  • 隐式锁定和解锁:使用 synchronized 关键字时,不需要显式地调用锁定和解锁方法(如 lock() 和 unlock())。当线程进入 synchronized 代码块或方法时,它会自动获得锁;当线程退出 synchronized 代码块或方法时,它会自动释放锁。这简化了并发编程的复杂性。

volatile的特点

  1. 保证可见性:当一个线程修改了 volatile 变量的值,这个新值会立即对其他线程可见。这是通过禁止 CPU 和编译器优化来实现的,确保了对共享变量的修改能够立即被其他线程看到。
  2. 禁止指令重排序:在程序运行时,为了提高性能,编译器和处理器可能会对指令进行重排序,但在多线程环境下,这可能导致逻辑错误。volatile 修饰的变量在读、写时会加入内存屏障,阻止其他读写操作越过屏障,从而达到阻止重排序的效果。
  3. 受限的原子性:对于单个 volatile 变量的读/写操作是原子的,但复合操作(如 i++)则不是。因此,在多线程环境中,volatile 并不能完全保证原子性。

 线程不安全问题及解决方案

线程不安全的原因

  1. 并发访问共享资源:多个线程在没有同步的情况下同时访问和修改同一份数据或资源,导致数据不一致和错误。

  2. 原子性问题:像count++这样的操作并不是原子的,它们由多个步骤组成(读取-修改-写入),这些步骤可能在多线程环境中被其他线程打断,导致数据不一致。

  3. 内存可见性问题:一个线程对共享变量的修改,对于其他线程来说可能不是立即可见的,这取决于JVM的内存模型和硬件的内存模型。

  4. 指令重排序:为了提高性能,编译器和处理器可能会对指令进行重排序,这种重排序在单线程环境中是安全的,但在多线程环境中可能导致问题。

解决方案

  1. 使用没有共享资源的模型

    如果线程之间不共享任何资源,那么它们之间的交互将非常简单,也就不需要担心线程安全问题。
  2. 使用共享资源只读,不写的模型

    • 不需要写共享资源的模型: 如果多个线程只读取共享资源而不进行修改,那么就不会出现数据不一致的问题
    • 使用不可变对象: 不可变对象一旦创建,其内容就不能被修改。因此,在多线程环境中,不可变对象是线程安全的。例如使用StringInteger等不可变类,或者自定义不可变类。
  3. 直接线程安全(重点)

    • 保证原子性: 原子性是指一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。使用synchronized等机制来确保操作的原子性。
    • 保证顺序性: 在多线程环境中,由于线程调度的不确定性,可能会出现操作顺序的问题。我们需要确保关键操作的顺序性。使用synchronized块、volatile关键字等机制来确保操作的顺序性
    • 保证可见性: 可见性是指当一个线程修改了某个变量的值,新值对于其他线程来说是立即可见的。使用volatile关键字确保当一个线程修改了共享变量的值后,其他线程能够立即看到这个修改。

wait() 和notify() 的作用

wait() 的作用

  • wait() 方法的主要作用是使当前线程进入等待(阻塞)状态,并释放对象的锁。这意味着,当线程调用某个对象的 wait() 方法时,它会放弃对该对象的锁,并进入等待状态,直到其他线程调用了该对象的 notify() 或 notifyAll() 方法。在等待期间,线程不会消耗CPU资源,因为它被暂停执行了。

notify() 的作用

  • notify() 方法的作用是唤醒在该锁上等待的单个线程(如果有的话)。被唤醒的线程会重新尝试获取对象的锁,并在成功获取锁后继续执行。需要注意的是,notify() 方法并不会立即释放对象的锁,而是在当前线程退出同步代码块或同步方法时释放。另外,notify() 方法只会唤醒一个等待的线程,如果有多个线程在等待,那么它会随机选择一个线程进行唤醒。

wait()和sleep()的对比

  • wait: 主要是在不知道要等多久的前提使用,所谓的超时时间是兜底用的,一般在这之前就被notify唤醒了,wait需要搭配synchronized使用,wait是Object方法
  • sleep: 一定是知道要多少时间的前提下使用,在时间到达之前是不会醒,除了异常情况的提前唤醒,sleep不用搭配synchronized使用,使用时候需要try-catch,sleep是Thread的静态方法

常见的锁策略 

  • 悲观锁:加锁钱预估锁冲突出现的概率大,因此加锁会做很多工作,加锁速度会慢,但是不容易出现问题,适用于锁冲突比较激烈的时候
  • 乐观锁:预估锁冲突出现的概率小,加锁前不做太多工作,加锁会快,但是容易引起其他问题导致消耗更多cpu资源,适用于锁冲突不激烈的时候
  • 重量级锁:类似悲观锁,加锁开销大且速度慢,
  • 轻量级锁:类似乐观锁,加锁开销小且加锁速度快

乐观悲观指的是对未发生的事情进行预估

重量级轻量级指的是加锁后对结果的评价,两种角5/度描述同一件事情

  • 自旋锁:轻量级的典型实现,如果获取锁失败,立即尝试加锁,无限循环,可以在其他线程释放锁的第一时间拿到锁,这种适用于锁冲突概率小的情况,也就是乐观锁
  • 挂起等待锁:重量级的典型实现,在获取锁失败的时候就加入等待队列,锁释放的时候再参与锁竞争中,同时也是悲观锁
  • 公平锁:简单理解就是,遵守先来后到,先来的线程先拿锁
  • 非公平锁:所有线程都需要参与锁竞争
  • 可重入锁:可以允许一个线程获取多把锁,多加锁也不会死锁
  • 不可重入锁:一个线程只能获取一把锁,多了就死锁了
  • 读写锁:包括读锁和写锁,加上读锁只能读,加上写锁当前线程只能写,允许多个线程读,但只允许一个线程写
  • 互斥锁:加锁期间只有一个线程能安全的访问共享资源

synchronized自身优化手段/synchronized实现原理

synchronized基本特点

        乐观锁/悲观锁自适应

        轻量级锁/重量级锁自适应

        自旋锁/挂起等待锁自适应

        非公平锁

        是可重入锁

        不是读写锁

加锁过程

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

  • 偏向锁阶段:(假设是没有资源过来竞争)核心要点,非必要不加锁,此时并直到加锁了,只是做了个轻量标记,没有竞争就省去了这个操作,如果有竞争就会过渡到轻量级锁阶段
  • 轻量级锁阶段:(假设有竞争但是不多),此时就是通过自旋锁的方式来实现,在其他线程释放锁的时候第一时间拿到锁,缺点消耗cpu,如果此时synchronized内部发现参与进程的线程比较多了就会进一步升级到重量级锁阶段
  • 重量级锁阶段:此时拿不到锁就不会自旋了,而是进入"阻塞等待",机会让出cpu资源,如果有线程释放锁,就会随机唤醒一个线程参与锁竞争

锁粗化

  • 粗细指的是锁的粒度粗细,也就是加锁代码涉及到的范围,{ }里的代码越多越粗
  • 一段程序出现多次加锁解锁操作,编译器+JVM就会自动进行锁粗化,把几个"小锁合并成一个大锁"

锁消除

  • 消除一些冗余的锁,消除的操作比较保守,只会那种一眼看着就是线程安全的代码进行消除

你是怎么理解乐观锁和悲观锁的,具体怎么实现呢?

  • 悲观锁认为多个线程访问同⼀个共享变量冲突的概率较⼤, 会在每次访问共享变量之前都去真正加锁.
  • 乐观锁认为多个线程访问同⼀个共享变量冲突的概率不⼤. 并不会真的加锁, ⽽是直接尝试访问数据.
  • 在访问的同时识别当前的数据是否出现访问冲突.
  • 悲观锁的实现就是先加锁(⽐如借助操作系统提供的 mutex), 获取到锁再操作数据. 获取不到锁就等待.
  • 乐观锁的实现可以引⼊⼀个版本号. 借助版本号识别出当前的数据访问是否冲突. 

介绍下读写锁?

  • 读写锁就是把读操作和写操作分别进⾏加锁.
  • 读锁和读锁之间不互斥.
  • 比特就业课写锁和写锁之间互斥.
  • 写锁和读锁之间互斥.
  • 读写锁最主要⽤在 "频繁读, 不频繁写" 的场景中.

什么是⾃旋锁,为什么要使⽤⾃旋锁策略呢,缺点是什么?

  • 如果获取锁失败, ⽴即再尝试获取锁, ⽆限循环, 直到获取到锁为⽌. 第⼀次获取锁失败, 第⼆次的尝试
  • 会在极短的时间内到来. ⼀旦锁被其他线程释放, 就能第⼀时间获取到锁.
  • 相⽐于挂起等待锁,
  • 优点: 没有放弃 CPU 资源, ⼀旦锁被释放就能第⼀时间获取到锁, 更⾼效. 在锁持有时间⽐较短的场景
  • 下⾮常有⽤.
  • 缺点: 如果锁的持有时间较⻓, 就会浪费 CPU 资源.

synchronized 是可重⼊锁么?

  • 是可重⼊锁.
  • 可重⼊锁指的就是连续两次加锁不会导致死锁.
  • 实现的⽅式是在锁中记录该锁持有的线程⾝份, 以及⼀个计数器(记录加锁次数). 如果发现当前加锁的线程就是持有锁的线程, 则直接计数⾃增

CAS

CAS是什么

在Java中,CAS(Compare and Swap)"比较和交换",也被称为无锁算法或乐观锁的一种实现。CAS操作用于解决并发环境下的数据竞争问题,特别是在多线程环境中对共享数据的访问和修改。

CAS操作包含三个参数:原数据(V)、旧的预期值(A)和需要修改的新值(B)。

1. CAS会比较A是否等于V

2. 如果比较相等,将B写入V,否则不做操作

3. 返回该操作是否成功

总结什么是CAS:

  • 全称Compare and Swap,是一种天然原子操作,用于实现多线程环境下的无锁数据结构。CAS操作通过一条CPU指令来同时完成“读取内存、比较是否相等、修改内存”这三个步骤,从而确保这三个步骤不会被其他线程打断或干扰,实现了对共享数据的原子性读写

CAS主要解决了以下问题:

  • 原子性问题:CAS操作可以保证对共享数据的原子性读写,从而避免了多线程并发访问时可能引发的数据不一致问题。
  • 支持无锁算法:CAS操作不涉及加锁,也就不会阻塞,死锁,提高效率,提高系统并发性能,合理使用也可以线程安全

CAS内在的ABA问题是什么

  • ABA问题指的是一个共享变量的值在操作期间从A变为B,然后再从B变回A,而CAS操作可能会错误地认为没有其他线程修改过这个值。

为了解决ABA问题,可以采用以下方法:

  • 给要修改的数据引⼊版本号. 在 CAS ⽐较数据当前值和旧值的同时, 也要⽐较版本号是否符合预期. 如果发现当前版本号和之前读到的版本号⼀致, 就真正执⾏修改操作, 并让版本号⾃增; 如果发现当前版本号⽐之前读到的版本号⼤, 就认为操作失败

JUC(java.util.concurrent) 

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

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

相关文章

常识判断1

1.法律 &#xff08;1&#xff09;行政法 &#xff08;2&#xff09;刑法 3.新公务员法 &#xff08;4&#xff09;宪法 &#xff08;5&#xff09;民法 &#xff08;6&#xff09;监察法 &#xff08;7&#xff09;婚姻法 &#xff08;8&#xff09;反不正当竞争法

二次元手游《交错战线》游戏拆解

交错战线游戏拆解案 游戏亮点即核心趣味 一、关键词&#xff1a; 回合制游戏、二次元、机甲、横板、剧情、养成、异星探索。 二、游戏亮点&#xff1a; 符合目标群体审美的原画。 三、核心趣味&#xff1a; 抽卡、肝或者氪金解锁新皮肤。 核心玩法及系统规则 核心玩法&…

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法,声称过高的电压是根本原因;补丁预计将于8月中旬推出【更新】

英特尔终于宣布了解决CPU崩溃和不稳定性问题的方法&#xff0c;声称过高的电压是根本原因&#xff1b;补丁预计将于8月中旬推出【更新】 英特尔官方宣布&#xff0c;已找到困扰其CPU的崩溃问题的根本原因&#xff0c;并将于8月中旬前发布微码更新以解决这一问题&#xff0c;从而…

Godot游戏制作 02玩家1.0版

Unity大神&#xff0c;YouTube百万游戏开发者的启蒙老师&#xff0c;Brackeys&#xff0c;携 Godot 新手教程&#xff0c;正式回归。 转自&#xff1a;https://youtu.be/LOhfqjmasi0?si4RguI6-pXHZ2mk9K 资产&#xff1a;https://brackeysgames.itch.io/brackeys-platformer-b…

uniapp上传图片修改头像操作

handleAvator() {uni.chooseImage({count: 1,sizeType: [original, compressed], //可以指定是原图还是压缩图&#xff0c;默认二者都有sourceType: [album, camera], //从相册选择success: (res) > {uni.uploadFile({url: this.baseUrl /system/dooruser/avatar,filePath:…

SpringBoot3整合Druid报错Cannot load driver class: org.h2.Driver

报错显示springboot自带的H2数据库报错&#xff0c;其实是因为druid并未加载进去。如果你其它配置都没问题的话&#xff0c;请检查druid的依赖是什么版本的&#xff0c;因为springboot3刚开始是不支持druid的。 方案一&#xff1a; 即需要手动在resources目录下创建META-INF/s…

Pure Storage首席技术官:存储、网络及软件数据集规模上正迅速接近可扩展性的极限

Pure Storage的欧洲、中东和非洲地区&#xff08;EMEA&#xff09;首席技术官Alex McMullan认为&#xff0c;我们在存储、网络及软件数据集规模上正迅速接近可扩展性的极限。在本月伦敦的一次简报会上&#xff0c;McMullan阐述了Pure Storage对可扩展性问题的立场&#xff0c;包…

java算法day20

java算法day20 701.二叉搜索树中的插入操作450.删除二叉搜索树中的节点108 将有序数组转换为二叉搜索树 本次的题目都是用递归函数的返回值来完成&#xff0c;多熟悉这样的用法&#xff0c;很方便。 其实我感觉&#xff0c;涉及构造二叉树的题目&#xff0c;用递归函数的返回值…

Stable Diffusion: 开启AI艺术创作的新纪元

在人工智能技术的不断演进中&#xff0c;Stable Diffusion作为一种新型的AI艺术生成模型&#xff0c;正在艺术创作和内容生产领域引起一场革命。Stable Diffusion通过深度学习技术&#xff0c;能够根据文本描述生成高质量、高分辨率的图像&#xff0c;为艺术家和设计师提供了一…

深入解析:端到端目标检测模型的奥秘

深入解析&#xff1a;端到端目标检测模型的奥秘 在人工智能领域&#xff0c;计算机视觉任务一直是研究的热点之一。目标检测作为计算机视觉中的核心问题&#xff0c;其重要性不言而喻。端到端的目标检测模型&#xff0c;以其高效的性能和简洁的架构&#xff0c;逐渐成为研究和…

优秀的Linux Shell终端Starship Shell的安装和配置

文章目录 简介安装startship1.安装 starship 二进制文件:2.将初始化脚本添加到您的 shell 的配置文件3、配置4、日志安装字体nerd-fonts编写脚本安装字体Nerd字体全量安装文档简介 Starship是一款轻量、迅速、可无限定制的高颜值终端! Starship Shell是一个用Rust编写的开源…

Redis 基数树

Redis 基数树&#xff08;Radix Tree&#xff09; 基数树&#xff08;Radix Tree&#xff09;&#xff0c;又称为紧凑前缀树或压缩前缀树&#xff0c;是一种高效的字符串存储和查询数据结构。Redis 使用基数树来实现其 Redis HyperLogLog 和 Redis Stream 数据类型的底层实现。…

visio 打开、插入、转换以及保存 DWG 和 DXF (AutoCAD) 绘图

打开、插入、转换以及保存 DWG 和 DXF (AutoCAD) 绘图 Visio 计划 2 Visio Professional 2021 Visio Standard 2021 Visio Professional 2019 更多... 如果要在 Visio 绘图中使用AutoCAD对象&#xff0c;可以使用 Visio 打开它们并将其转换为 Visio 形状。 还可以将 Visio 绘…

图灵测试:人工智能与人类沟通的界限

图灵测试是评估人工智能&#xff08;AI&#xff09;是否能够表现出与人类相似的智能的重要标准之一。它由英国数学家兼计算机科学家艾伦图灵在1950年提出&#xff0c;其核心目的是测试一个机器是否能够表现出类似于人类思维的能力&#xff0c;从而模拟人类的智能。这一测试也因…

汇编语言例题分析

以下数据段定义了如下数据&#xff0c;对应内存图请填空&#xff0c;写出每个内存字节中的2位16进制数&#xff08;注意写准确&#xff0c;2位16进制数&#xff0c;末尾不带h&#xff09;。 Data1 segment x db 1,2,3 y db “ABa” z dw 1,2 Data1 ends 物理地址从0000开始&…

每日任务:报文构成、请求类型及GET与POST差异分析

1.HTTP请求报文和响应报文是怎样的&#xff0c;有哪些常见的字段&#xff1f; HTTP报文分为请求报文和响应报文&#xff1b; &#xff08;1&#xff09;请求报文主要由请求行、请求头、空行、请求体构成。 请求行包括了&#xff1a; 请求方式&#xff1a;如get、post、put、…

PostgreSQL异常:An I/O error occurred while sending to the backend

在使用PostgreSQL数据库批量写入数据的时候&#xff0c;遇到了一个问题&#xff0c;异常内容如下&#xff1a; Cause: org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.报错内容 报错提示1 Caused by: org.postgresql.util.PSQLExc…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-25 ADC模块FEP-DAQ9248采集显示波形方案

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

网络编程之LINUX信号

网络编程中 Linux 信号&#xff1a; 一、信号概述 信号是 Linux 操作系统中一种异步的事件通知机制&#xff0c;用于在进程之间传递消息或指示某种系统状态的变化。它允许内核在特定条件发生时中断进程的正常执行流程&#xff0c;并调用相应的信号处理函数。 二、Linux 信号的分…

MTK 安卓14 launcher3修改桌面模式,替换某些应用图标,以及定制化Hotseat

原生的launcher的Hotseat如下图(1)所示,我想把效果改成图(2) 图(1) 图(2) 一:定制化HotSeat 修改的类&#xff1a;packages/apps/Launcher3/com/android/launcher3/Hotseat.java &#xff08;1&#xff09;.修改hotseat的宽 Hotseat------->setInsetsOverridepublic void…