当前位置: 首页 > news >正文

聊聊并发编程——多线程之synchronized

目录

一.多线程下数据不一致问题

二.锁和synchronized

2.1 并发编程三大特性

2.2引入锁概念

三.synchronized的锁实现原理

3.1 monitorenter和monitorexit

3.2synchronized 锁的升级

3.2.1偏向锁的获取和撤销

3.2.2轻量级锁的加锁和解锁

自适应自旋锁

轻量级锁的解锁

3.2.3重量级锁—线程阻塞

3.2.4锁的优缺点对比

3.3CAS实现原子性


一.多线程下数据不一致问题

我们知道,在并发编程中,多个线程同时访问共享资源时可能导致数据不一致、死锁、性能问题等严重后果。

像下面这个例子,i的值最后是多少呢?

简单的demo实验下:

public class Demo {private static int count = 0;public static void inc() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}count++;}
​public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 100; i++) {new Thread(() -> Demo.inc()).start();}Thread.sleep(3000);System.out.println("运行结果" + count);}
}

多次的运行结果是不相同的,并不是预期的100:

针对数据不一致的问题,我们先了解下java内存模型(Java Memory Model, JMM),它是一种抽象的模型,被定义出来屏蔽各种硬件和操作系统的内存访问差异。JMM定义了线程与主内存之间的抽象关系:线程之间的共享变量存储在主内存中,而每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。

结合JMM不难理解,线程t1和t2通过操作本地内存中的副本进行刷新存储在主内存上的共享变量对象,但它们都没有在进行修改操作后立即告知其它线程。针对多线程并发访问共享资源导致数据不一致的问题,java给出了类似Synchronized和volatile的解决方案。

二.锁和synchronized

2.1 并发编程三大特性

并发编程中有三大核心特性,分别是原子性(Atomicity)、可见性(Visibility)、有序性(Ordering),通常被简称为 AVO 特性。这些特性对于多线程编程非常重要,因为它们确保了多线程环境下的正确性和可靠性。

  1. 原子性(Atomicity):

    • 原子性指的是一个操作是不可分割的单元,要么全部执行成功,要么全部不执行,不会被中断。原子操作可以看作是线程安全的,多个线程可以同时执行这个操作,而不会破坏操作的完整性。

    • 原子性保证了操作的完整性,避免了竞态条件,通常通过锁、原子类、事务等机制来实现。

  2. 可见性(Visibility):

    • 可见性指的是一个线程对共享变量的修改能够被其他线程立即感知到,即修改后的值在主内存中对其他线程是可见的。在多线程环境下,如果不采取适当的同步措施,共享变量的修改可能对其他线程不可见,导致意外的行为和错误。

    • 可以使用volatile关键字来确保变量的可见性,或者使用锁机制(如synchronized关键字)来同步访问共享变量。

  3. 有序性(Ordering):

    • 有序性指的是程序的执行顺序与代码的编写顺序一致,即代码按照预期的顺序执行,不会出现乱序或重排序的情况。

    • 在现代计算机架构中,为了提高性能,编译器和处理器可能会对指令进行重排序,但这种重排序在单线程环境下不会引发问题。然而,在多线程环境下,如果不正确地控制重排序,可能会导致不一致的结果。

    • 可以使用同步机制来确保有序性,例如在进入和退出锁的范围内,编译器和处理器会执行必要的指令重排序来维护有序性。

2.2引入锁概念

在可见性的理解上,java引入了锁的概念,用于防止多个线程同时访问或修改共享资源,以确保线程安全性。

而加锁的方式是使用synchronized关键字。

public class Demo {private static int count = 0;// 使用Synchronized加锁public static synchronized void inc() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}count++;}
​public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 100; i++) {new Thread(() -> Demo.inc()).start();}Thread.sleep(3000);System.out.println("运行结果" + count);}
}

synchronized 关键字在 Java 中主要用于实现互斥锁,它主要保证了并发编程中的原子性和可见性这两个特性。

  1. 原子性(Atomicity):

    synchronized 保证了被 synchronized 修饰的代码块或方法在同一时间只能被一个线程执行,这确保了其中的操作是原子的,即不会被中断或同时被其他线程访问。这有助于防止竞态条件和确保操作的完整性。

  2. 可见性(Visibility):

    当一个线程进入 synchronized 块或方法时,它会获取锁,并在释放锁时将修改的数据从线程的工作内存同步到主内存,这就确保了其他线程可以立即看到最新的数据。这满足了可见性要求,确保了共享数据的变更对其他线程是可见的。

synchronized 关键字在 Java 中有三种主要的用法,用于实现不同类型的同步:

  1. 实例方法同步:

    使用 synchronized 关键字修饰普通的实例方法,这会将锁定范围限制在该方法所属对象实例上,即同一对象的不同线程在同时访问这个方法时会互斥执行。这种方式适用于对实例变量的同步访问。

    public synchronized void instanceMethod() {// 这里的代码是线程安全的
    }
  2. 静态方法同步:

    使用 synchronized 关键字修饰静态方法,这会将锁定范围限制在类的 Class 对象上,即同一类的不同对象的不同线程在同时访问这个静态方法时会互斥执行。这种方式适用于对静态变量的同步访问。

    public static synchronized void staticMethod() {// 这里的代码是线程安全的
    }
  3. 同步代码块:

    使用 synchronized 关键字修饰代码块,可以精确地指定需要同步的对象。这允许你在方法内的特定部分实现同步,而不是整个方法。你需要指定一个对象作为锁,当多个线程尝试进入同步代码块时,它们必须获取相同的锁才能执行。

    public void someMethod() {// 一些非同步代码synchronized (lockObject) {// 这里的代码是线程安全的,锁定的是 lockObject 对象}// 更多非同步代码
    }

    设计模式中

    [单例模式的双重检查锁定]  https://blog.csdn.net/Elaine2391/article/details/132675080 

    其实就是一个简单的Synchronized和volatile的应用。

三.synchronized的锁实现原理

3.1 monitorenter和monitorexit

我们使用synchronized的时候没有手动的lock和unlock,那么synchronized是怎么加锁的呢?其实这里JVM帮我们处理了。反编译⼀段synchronized修饰代码块代码来看看:

找到上面我们的Demo类文件路径,javac Demo.java后生成class文件, javap -v Demo.class ,可以看到相应的字节码指令。synchronized修饰静态方法时,JVM采用monitorenter和monitorexit两个指令来实现同步,monitorenter 指令指向同步代码块的开始位置, monitorexit 指令则指向同步代码块的结束位置。

而且synchronized修饰同步方法时,JVM采用ACC_SYNCHRONIZED标记符实现同步,这个标识指明了该方法是一个同步方法。

monitorenter、monitorexit或者ACC_SYNCHRONIZED都是基于Monitor实现的。Monitor是什么呢?

所谓的Monitor其实是⼀种同步⼯具,也可以说是⼀种同步机制。在Java虚拟机(HotSpot)中,Monitor是由 ObjectMonitor实现的,可以叫做内部锁,或者Monitor锁。线程在获取锁的时候,实际上就是获得一个监视器对象(monitor),monitor可以认为是一个同步对象,所有的Java对象是天生携带monitor。多个线程访问同步代码块时,相当于去争抢对象监视器修改对象中的锁标识,ObjectMonitor这个对象和线程争抢锁的逻辑有密切的关系。

3.2synchronized 锁的升级

在JVM的自动内存管理中分析markword时,提到了偏向锁、轻量级锁、重量级锁和无锁状态。分析前我们先来思考一个问题:使用锁能够实现数据的安全性,但是会带来性能的下降。不使用锁能提高性能又不能保证线程安全性。怎么办呢?

其实hotspot的作者经过调查发现,假设加锁的同步块分为下面三种情况,而大部分情况下,是处于第一种。

  1. 只有线程A进入临界区。(偏向锁)

  2. 线程A和线程B交替进入临界区。(轻量级锁)

  3. 线程A、线程B、线程C同时进入临界区。(重量级锁)

而这也是JDK1.6之后synchronized做出的优化,为了减少获得锁和释放锁带来的性能开销,引入了偏向锁、轻量级锁的概念。所以synchronized中,锁存在四种状态,分别是无锁、偏向锁、轻量级锁、重量级锁;锁的状态根据竞争激烈的程度从低到高不断升级。

针对共享资源对象加锁的操作,其实真正操作的是对象头中的markword。

img

3.2.1偏向锁的获取和撤销
  • 首先获取锁对象的Markword,判断是否处于可偏向状态。(偏向锁位biased_lock=0且ThreadId为空,表示未偏向任何线程)

  • 如果是可偏向状态,则通过CAS操作,把当前线程的ID写入到Markword

    a)如果CAS成功,那么就表示线程获取了锁对象的偏向锁,锁状态从无锁升级为偏向锁。

    b)如果CAS失败,说明其他线程已获得了偏向锁。这种情况说明当前存在锁竞争,需要暂停已获得偏向锁的线程,撤销偏向锁,升级为轻量级锁(这个操作在全局安全点执行,就是没有线程在执行字节码的时候)

  • 如果是已偏向状态,需要检查Markword中存储的ThreadId是否等于当前线程的ThreadId

    a)如果相等,不需要再次获得锁,可直接执行同步代码块。这就避免了锁的竞争和线程上下文切换。

    b)如果不相等,说明当前锁偏向于其他线程,需要撤销锁并升级为轻量级锁

对于原持有偏向锁的线程进行撤销时,原获得偏向的线程有两种情况:

a)原获得偏向锁的线程已经退出了临界区,就是执行完了代码块,这时候就会把对象头设置为无锁状态,并且争抢锁的进程可以基于CAS重新设置对象头偏向当前线程。

b)原获得偏向锁的线程还在执行同步块,这个时候就会将原获得偏向锁的线程的偏向锁升级为轻量级锁。

但是根据我们实际情况,绝大部分时候一定会存在2个以上的线程竞争,那么开启偏向锁反而提升了获取锁的资源消耗,可以通过jvm参数UserBiasedLocking来设置开启或关闭偏向锁。流程图分析如下:

3.2.2轻量级锁的加锁和解锁
  • 首先,jvm会判断是否是重量级锁,如果不是,会在当前线程栈帧中划出一块空间,作为该锁的锁记录,并且将锁对象Markword复制到该锁记录中。

  • 复制成功后,jvm使用CAS操作将对象头Markword更新为指向锁记录的指针,并且将锁记录里的own指针指向对象头的Markword。

  • 更新对象头Markword成功的情况,当前线程持有对象锁,并且对象Markword锁标志设为‘00’,即表示此对象处于轻量级锁状态。

  • 更新对象头Markword失败的情况,jvm先检查对象MarkWord是否指向当前线程栈帧中的锁记录,如果是就表示锁重入。如果不是就表示锁对象被其他线程抢占,进行自旋等待(默认10次),等待次数达到阈值仍未获取到锁,膨胀为重量级锁。

自适应自旋锁

自旋锁就是锁在原地循环执行一个啥都没有的for循环操作,是会消耗cpu的。JDK1.6后引入了自适应自旋锁,自适应意味着着自旋的次数不是固定不变的,而是根据前一次在同一个锁上自旋的时间以及锁的拥有者的状态来决定。

如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自

旋也是很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。

如果对于某个锁,自旋很少成功获得过,那在以后尝试获取这个锁时将可能省略掉自旋过程,直接阻塞线程,避免浪费处理器资源。

轻量级锁的解锁

就是获得锁的逆向逻辑,通过CAS操作把栈帧中的LockRecord替换回锁对象的Markword中,如果成功表示没有竞争。如果失败,表示当前锁存在竞争,那么轻量级锁就会膨胀为重量级锁。流程图如下:

3.2.3重量级锁—线程阻塞

轻量级锁膨胀到重量级锁后,线程只能被挂起阻塞来等待被唤醒了。阻塞是重量级锁的标志。重量级锁加锁的基本流程:

举例说明下:

定义线程A传入锁对象lock,包含一个简单的wait操作。

public class ThreadA extends Thread{private Object lock;public  ThreadA(Object lock){this.lock = lock;}@Overridepublic void run() {synchronized (lock) {System.out.println("ThreadA start");try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("ThreadA end");}}
}

定义线程B传入锁对象,包含一个notify操作。

public class ThreadB extends Thread{private Object lock;public ThreadB(Object lock){this.lock = lock;}@Overridepublic void run() {synchronized (lock) {System.out.println("ThreadB start");lock.notify();System.out.println("ThreadB end");}}
}

创建A线程启动,B线程启动,执行结果:

public class WaitNotify {public static void main(String[] args) {Object lock = new Object();ThreadA threadA = new ThreadA(lock);threadA.start();
​ThreadB threadB = new ThreadB(lock);threadB.start();}
}

3.2.4锁的优缺点对比

3.3CAS实现原子性
  • CAS叫做CompareAndSwap,⽐较并交换,主要是通过处理器的指令来保证操作的原⼦性的。

  • CAS 指令包含 3 个参数:共享变量的内存地址 A、预期的值 B 和共享变量的新值 C。

  • 只有当内存中地址 A 处的值等于 B 时,才能将内存中地址 A 处的值更新为新值 C。作为⼀条 CPU 指令,CAS 指令 本身是能够保证原⼦性的

CAS操作三大问题

  • ABA问题,在比较期间,发生了A-B-A,CAS感知不到过程,解决方案:加版本号。1A-2B-3A.

  • 循环时间长开销大

  • 只能保证一个共享变量的原子操作

相关文章:

聊聊并发编程——多线程之synchronized

目录 一.多线程下数据不一致问题 二.锁和synchronized 2.1 并发编程三大特性 2.2引入锁概念 三.synchronized的锁实现原理 3.1 monitorenter和monitorexit 3.2synchronized 锁的升级 3.2.1偏向锁的获取和撤销 3.2.2轻量级锁的加锁和解锁 自适应自旋锁 轻量级锁的解锁…...

CompletableFuture-通用异步编程

演示Completable接口完全可以代替Future接口&#xff1a; CompletableFuture减少阻塞和轮询&#xff0c;可以传入回调对象&#xff0c;当异步任务完成或者发生异常时&#xff0c;自动 调用回调对象的回调方法。 package com.nanjing.gulimall.zhouyimo.test;import java.util…...

Vue3 封装 element-plus 图标选择器

一、实现效果 二、实现步骤 2.1. 全局注册 icon 组件 // main.ts import App from ./App.vue; import { createApp } from vue; import * as ElementPlusIconsVue from element-plus/icons-vueconst app createApp(App);// 全局挂载和注册 element-plus 的所有 icon app.con…...

超详细C语言实现——通讯录

目录 一、介绍 二、源代码 test.c: Contact.c: Contact.h: 代码运行结果&#xff1a; 三、开始实现 1.基本框架&#xff1a; 2.添加联系人&#xff1a; 3.显示联系人信息&#xff1a; 4.删除联系人信息&#xff1a; 5.查看指定联系人信息&#xff1a; 6.修改联系人…...

zabbix监控添加监控项及其监控Mysql、nginx

本届主要介绍添加监控项和修改中文乱码&#xff0c;监控mysql&#xff0c;nginx服务 一、zabbix监控添加监控项 1、配置agent服务器 在配置文件中添加&#xff1a; UserParameterlsq_userd,free -m | grep Mem | awk { print $3 } 服务器内存使用量 UserParameterdu,…...

Docker 部署 MongoDB 服务

拉取最新版本的 MongoDB 镜像&#xff1a; $ sudo docker pull mongo:latest在本地预先创建好 db 和 configdb 目录, 用于映射 MongoDB 容器内的 /data/db 和 /data/configdb 目录。 使用以下命令来运行 MongoDB 容器: $ sudo docker run -itd --name mongo --privilegedtru…...

QUIC协议报文解析(三)

在前面的两篇文字里我们简单介绍了QUIC的发展历史&#xff0c;优点以及QUIC协议的连接原理。本篇文章将会以具体的QUIC报文为例&#xff0c;详细介绍QUIC报文的结构以及各个字段的含义。 早期QUIC版本众多&#xff0c;主要有谷歌家的gQUIC&#xff0c;以及IETF致力于将QUIC标准…...

pytorch迁移学习训练图像分类

pytorch迁移学习训练图像分类 一、环境配置二、迁移学习关键代码三、完整代码四、结果对比 代码和图片等资源均来源于哔哩哔哩up主&#xff1a;同济子豪兄 讲解视频&#xff1a;Pytorch迁移学习训练自己的图像分类模型 一、环境配置 1&#xff0c;安装所需的包 pip install …...

SQL 如何提取多级分类目录

前言 POI数据处理&#xff0c;原始数据为csv格式&#xff0c;整理入库至PostGreSQL&#xff0c;本例使用PostGreSQL13版本。 一、POI POI&#xff08;一般作为Point of Interest的缩写&#xff0c;也有Point of Information的说法&#xff09;&#xff0c;通常称作兴趣点&am…...

从中序遍历和后序遍历构建二叉树

题目描述 106. 从中序与后序遍历序列构造二叉树 中等 1.1K 相关企业 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1…...

《计算机视觉中的多视图几何》笔记(11)

11 Computation of the Fundamental Matrix F F F 本章讲述如何用数值方法在已知若干对应点的情况下求解基本矩阵 F F F。 文章目录 11 Computation of the Fundamental Matrix F F F11.1 Basic equations11.1.1 The singularity constraint11.1.2 The minimum case – sev…...

UE5 ChaosVehicles载具研究

一、基本组成 载具Actor类名称&#xff1a;WheeledVehiclePawn Actor最原始的结构 官方增加了两个摇臂相机&#xff0c;可以像驾驶游戏那样切换多机位、旋转观察 选择骨骼网格体、动画蓝图类、开启物理模拟 二、SportsCar_Pawn 角阻尼&#xff1a;物体旋转的阻力。数值越大…...

数据通信——应用层(域名系统)

引言 TCP到此就告一段落&#xff0c;这也意味着传输层结束了&#xff0c;紧随其后的就是TCP/IP五层架构的应用层。操作系统、编程语言、用户的可视化界面等等都要通过应用层来体现。应用层和我们息息相关&#xff0c;我们使用电子设备娱乐或办公时&#xff0c;接触到的就是应用…...

Visual Studio 更新:远程文件管理器

Visual Studio 中的远程文件管理器可以用来访问远程机器上的文件和文件夹&#xff0c;通过 Visual Studio 自带的连接管理器&#xff0c;可以实现不离开开发环境直接访问远程系统&#xff0c;这确实十分方便。 自从此功能发布以来&#xff0c;VS 开发团队努力工作&#xff0c;…...

ChatGPT追祖寻宗:GPT-3技术报告要点解读

论文地址&#xff1a;Language Models are Few-Shot Learners 往期相关文章&#xff1a; ChatGPT追祖寻宗&#xff1a;GPT-1论文要点解读_五点钟科技的博客-CSDN博客ChatGPT追祖寻宗&#xff1a;GPT-2论文要点解读_五点钟科技的博客-CSDN博客 本文的标题之所以取名技术报告而不…...

java easyexcel 导出多级表头

maven <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>${easyexcel.version}</version> </dependency> 导出行的对象 import com.alibaba.excel.annotation.ExcelIgnore; import …...

rar格式转换zip格式,如何做?

平时大家压缩文件时对压缩包格式可能没有什么要求&#xff0c;但是&#xff0c;可能因为工作需要&#xff0c;我们要将压缩包格式进行转换&#xff0c;那么我们如何将rar格式转换为其他格式呢&#xff1f;方法如下&#xff1a; 工具&#xff1a;WinRAR 打开WinRAR&#xff0c…...

Java中的构造方法

在Java中&#xff0c;构造方法是类的特殊方法&#xff0c;用于初始化对象的实例变量和执行其他必要的操作&#xff0c;以便使对象能够正确地工作。构造方法与类同名&#xff0c;没有返回类型&#xff0c;并且在创建对象时自动调用。 以下是构造方法的一些基本特性&#xff1a;…...

【Java】fastjson

Fastjson简介 Fastjson是阿里巴巴的团队开发的一款Java语言实现的JSON解析器和生成器&#xff0c;它具有简单易用、高性能、高可用性等优点&#xff0c;适用于Java开发中的数据解析和生成。Fastjson的主要特点包括&#xff1a; 简单易用&#xff1a;Fastjson提供了简单易用的…...

JMeter之脚本录制

【软件测试面试突击班】如何逼自己一周刷完软件测试八股文教程&#xff0c;刷完面试就稳了&#xff0c;你也可以当高薪软件测试工程师&#xff08;自动化测试&#xff09; 前言&#xff1a; 对于一些JMeter初学者来说&#xff0c;录制脚本可能是最容易掌握的技能之一。…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

FOPLP vs CoWoS

以下是 FOPLP&#xff08;Fan-out panel-level packaging 扇出型面板级封装&#xff09;与 CoWoS&#xff08;Chip on Wafer on Substrate&#xff09;两种先进封装技术的详细对比分析&#xff0c;涵盖技术原理、性能、成本、应用场景及市场趋势等维度&#xff1a; 一、技术原…...

起重机起升机构的安全装置有哪些?

起重机起升机构的安全装置是保障吊装作业安全的关键部件&#xff0c;主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理&#xff1a; 一、超载保护装置&#xff08;核心安全装置&#xff09; 1. 起重量限制器 功能&#xff1a;实时监测起升载荷&a…...