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

JUC并发编程19 | 读写锁

有一些关于锁的面试题:

  1. 你知道 Java 里面有哪些锁?
  2. 读写锁的饥饿问题是什么?
  3. 有没有比读写锁更快的锁?
  4. StampedLock知道嘛?(邮戳锁/票据锁)
  5. ReentrantReadWriteLock 有锁降级机制?

ReentrantReadWriteLock

与 ReentrantLock 相比,ReentrantLock 实现了 Lock 接口,ReentrantReadWriteLock 实现了 ReadWriteLock 接口。对于ReentrantLock 它的 读读也是一个线程访问,浪费资源。ReentrantReadWriteLock 可以实现读读共享!

读写锁定义为:一个资源能被多个读线程访问,或者被一个写线程访问,但是不能同时存在读写线程(读写互斥,读读共享)

class MyRescource {  // 资源类模拟缓存Map<String, String> map = new HashMap<>();// ========= ReentrantLock 等价于 ======== SynchronizedLock lock = new ReentrantLock();// ========= ReentrantReadWritLock =======读读共享ReadWriteLock readWriteLock = new ReentrantReadWriteLock();public void write(String key, String value) {lock.lock();try{System.out.println(Thread.currentThread().getName()+"\t正在写入。。。。");map.put(key,value);try {TimeUnit.MILLISECONDS.sleep(1000);System.out.println(Thread.currentThread().getName()+"\t完成写入。。。。");}catch (InterruptedException e){e.printStackTrace();}}finally {lock.unlock();}}public void readWriteWrite(String key, String value) {readWriteLock.writeLock().lock();try{System.out.println(Thread.currentThread().getName()+"\t正在写入。。。。");map.put(key,value);try {TimeUnit.MILLISECONDS.sleep(1000);System.out.println(Thread.currentThread().getName()+"\t完成写入。。。。");}catch (InterruptedException e){e.printStackTrace();}}finally {readWriteLock.writeLock().unlock();}}public void read(String key) {lock.lock();try{System.out.println(Thread.currentThread().getName()+"\t正在读入。。。。");String s = map.get(key);try {// 1. 暂停500毫秒// 2. 暂停2000毫秒,显式读锁没有完成之前,写锁无法获取锁TimeUnit.MILLISECONDS.sleep(2000);System.out.println(Thread.currentThread().getName()+"\t完成读入。。。。\t"+s);}catch (InterruptedException e){e.printStackTrace();}}finally {lock.unlock();}}public void readWriteRead(String key) {readWriteLock.readLock().lock();try{System.out.println(Thread.currentThread().getName()+"\t正在读入。。。。");String s = map.get(key);try {// 1. 暂停500毫秒// 2. 暂停2000毫秒,显式读锁没有完成之前,写锁无法获取锁TimeUnit.MILLISECONDS.sleep(2000);System.out.println(Thread.currentThread().getName()+"\t完成读入。。。。\t"+s);}catch (InterruptedException e){e.printStackTrace();}}finally {readWriteLock.readLock().unlock();}}
}public class ReentrantReadWriteLockDemo {public static void main(String[] args) {MyRescource myRescource = new MyRescource();for (int i = 0; i < 10; i++) {int finalI = i;new Thread(()->{// myRescource.write("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));myRescource.readWriteWrite("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));},String.valueOf(i)).start();}for (int i = 0; i < 10; i++) {int finalI = i;new Thread(()->{// myRescource.read("key"+String.valueOf(finalI));myRescource.readWriteRead("key"+String.valueOf(finalI));},String.valueOf(i)).start();}try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}// 显式读锁没有完成之前,写锁无法获取锁for (int i = 0; i < 3; i++) {int finalI = i;new Thread(()->{// myRescource.write("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));myRescource.readWriteWrite("key"+String.valueOf(finalI),"value"+String.valueOf(finalI));},"新读写锁"+String.valueOf(i)).start();}}
}

锁降级

ReentrantReadWriteLock锁降级:将写入锁降级为读锁(类似Linux文件读写权限理解,就像写权限要高于读权限一样),锁的严苛程度变强叫做升级,反之叫做降级。

重进入:该锁支持重进入,以读写线程为例:读线程在获取了读锁之后,能够再次获取读锁。而写线程在获取了写锁之后能够再次获取写锁,同时也可以获取读锁。

锁降级:遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级成为读锁

写锁的降级,降级成为了读锁

  1. 如果同一个线程持有了写锁,在没有释放写锁的情况下,它还可以继续获得读锁。这就是写锁的降级,降级成为了读锁。
  2. 规则惯例,先获取写锁,然后获取读锁,再释放写锁的次序。
  3. 如果释放了写锁,那么就完全转换为读锁。

保证数据的一致性

/**
所降级遵循了获取写锁,在获取读锁,再释放写锁的次序,写锁能够降级为读锁。因为写的优先级比读高
如果一个线程占有了写锁,在不释放写锁的情况下,它还能占有读锁,即写锁降级为读锁
读没有完成时候写锁无法获得锁,只有在读锁读完才可以
*/
public void lockLevelDown(){ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();writeLock.lock();System.out.println("写入");readLock.lock();System.out.println("读入");writeLock.unlock();readLock.unlock();readLock.lock();System.out.println("读入");writeLock.lock();System.out.println("写入");readLock.unlock();writeLock.unlock();
}
/**
写入
读入
读入
*/

分析StampedLock,会发现它改进之处在于:

读的过程中也允许获取写锁介入(相当牛B,读和写两个操作也让你“共享”(注意引亏)),这样会守致戎们实的数掂趴可能个一以所以,需要额外的方法来判断读的过程中是否有写入,这是一种乐观的读锁。

显然乐观锁的并发效率更高,但一旦有小概率的写入导致读取的数据不一致,需要能检测出来,再读一遍就行。

为什么要锁降级?

锁降级的必要性1:

锁降级中读锁的获取是否必要呢?答案是必要的。主要是为了保证数据的可见性,如果当前线程不获取读锁而是直接释放写锁, 假设此刻另一个线程(记作线程T)获取了写锁并修改了数据,那么当前线程无法感知线程T的数据更新。如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行数据更新。

部分人读完上述话可能有些疑惑,针对上面黑体字那句话,为什么无法感知线程T的数据更新?我当前线程再次获取读锁的时候不是可以察觉到数据在主存中的变化吗? 我参考了一些资料,对该 “”数据可见性“” 有了另一种理解,理解是 当前线程为了保证数据的可见性,这是指线程自己更改了数据,自己应该要察觉到数据的变化,如果没有读锁,更改完数据之后线程T获取到了写锁并更改了数据,则当前线程读到的数据是线程T更改的,并不是自己更改的,当前线程并不知道是线程T修改了自己要读的(原来自己改的)数据,所以可能导致当前线程在执行后续代码的时候结果出错,这时就导致了数据的不可见,即当前线程并无法察觉到自己修改的值!

锁降级的必要性2:

为了提高程序执行性能,可能存在一个事务线程不希望自己的操作被别的线程中断,而这个事务操作可能分成多部分操作更新不同的数据(或表)甚至非常耗时。如果长时间用写锁独占,显然对于某些高响应的应用是不允许的,所以在完成部分写操作后,退而使用读锁降级,来允许响应其他进程的读操作。只有当全部事务完成后才真正释放锁。

StampedLock

邮戳锁、版本锁是比读写锁更快的锁。

StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中读写锁ReentrantReadWriteLock的优化。

stamp(戳记,long 类型):代表了锁的状态。当stamp返回零时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值。

锁饥饿问题:ReentrantReadWriteLock实现了读写分离,但是一旦读操作比较多的时候,想要获取写锁就变得比较困难了,假如当前1000个线程,999个读,1个写,有可能999个读取线程长时间抢到了锁,那1个写线程就悲剧了因为当前有可能会一直存在读锁,而无法获得写锁,根本没机会写。

如何缓解锁饥饿问题:

  • 使用“公平”策略可以一定程度上缓解这个问题 new ReentrantReadWriteLock(true)
  • 但是“公平"策略是以牺牲系统吞吐量为代价

StampedLock 类的乐观读锁:对于短的制度代码段,使用乐观模式通常可以减少争用并提高吞吐量

ReentrantReadWriteLock

允许多个线程同时读,但是只允许一个线程写,在线程获取到写锁的时候,其他写操作和读操作都会处于阻塞状态,

读锁和写锁也是互斥的,所以在读的时候是不允许写的,读写锁比传统的synchronized速度要快很多,

原因就是在于ReentrantReadWriteLock支持读并发,读读可以共享

StampedLock横空出世

ReentrantReadWriteLock的读锁被占用的时候,其他线程尝试获取写锁的时候会被阻塞。

但是,StampedLock采取乐观获取锁后,其他线程尝试获取写锁时不会被阻塞,这其实是对读锁的优化,

所以,在获取乐观读锁后,还需要对结果进行校验。

StampedLock的特点

所有获得锁的方法,都返回一个邮戳(Stamp),Stamp为零表示获取失败,其余都表示成功

所有释放锁的方法,都需要一个邮戳(Stamp),这个Stamp必须是和成功获取锁时得到的Stamp一致

StampedLock 是不可重入的,危险(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)

StampedLock 有三种访问模式:

  1. Reading(读模式悲观):功能和ReentrantReadWriteLock 的读锁类似
  2. Writeing(写模式):功能和ReentrantReadWriteLock 的写锁类似
  3. Optimistic reading(乐观读模式):无锁机制,类似于数据库中的乐观锁,支持读写并发,很乐观认为读取时没人修改,假如被修改再实现升级为悲观读模式——读的过程中也允许获取写锁介入

邮戳读写锁的传统版本

public class StampedLockDemo {static int number = 37;static StampedLock stampedLock = new StampedLock();public void write(){long stamp = stampedLock.writeLock();System.out.println(Thread.currentThread().getName()+"\t 写线程准备修改。");try{number = number + 13;} finally {stampedLock.unlockWrite(stamp);}System.out.println(Thread.currentThread().getName()+"\t 写线程结束修改。");}public void read(){long stamp = stampedLock.readLock();System.out.println(Thread.currentThread().getName()+"\t 悲观读线程准备修改。..");try{for (int i = 0; i < 4; i++) {TimeUnit.SECONDS.sleep(1);System.out.println("读线程正在读取中");}int result = number;System.out.println(Thread.currentThread().getName()+"\t 悲观读线程结束修改。result = "+result);System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统读写互斥");} catch (InterruptedException e) {e.printStackTrace();} finally {stampedLock.unlockRead(stamp);}}public static void main(String[] args) {StampedLockDemo demo = new StampedLockDemo();new Thread(()->{demo.read();},"读线程").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{demo.write();},"写线程").start();}}
/**
读线程	 悲观读线程准备修改。..
读线程正在读取中
读线程正在读取中
读线程正在读取中
读线程正在读取中
读线程	 悲观读线程结束修改。result = 37
写线程没有修改成功,读锁时候写锁无法介入,传统读写互斥
写线程	 写线程准备修改。
写线程	 写线程结束修改。
*/

邮戳锁乐观版本

public class StampedLockDemo {static int number = 37;static StampedLock stampedLock = new StampedLock();public void write(){long stamp = stampedLock.writeLock();System.out.println(Thread.currentThread().getName()+"\t 写线程准备修改。");try{number = number + 13;} finally {stampedLock.unlockWrite(stamp);}System.out.println(Thread.currentThread().getName()+"\t 写线程结束修改。");}public void read(){long stamp = stampedLock.readLock();System.out.println(Thread.currentThread().getName()+"\t 悲观读线程准备修改。..");try{for (int i = 0; i < 4; i++) {TimeUnit.SECONDS.sleep(1);System.out.println("读线程正在读取中");}int result = number;System.out.println(Thread.currentThread().getName()+"\t 悲观读线程结束修改。result = "+result);System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统读写互斥");} catch (InterruptedException e) {e.printStackTrace();} finally {stampedLock.unlockRead(stamp);}}public void tryOptimisticRead(){long stamp = stampedLock.tryOptimisticRead();int result = number;System.out.println("4秒前stampedLock.validate方法值 (true无修改,false有修改)\t"+stampedLock.validate(stamp));for (int i = 0; i < 4; i++) {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"\t正在读取"+i+"秒,后stampedLock.validate方法值\t"+stampedLock.validate(stamp));}if (!stampedLock.validate(stamp)){System.out.println("有人修改------有写操作");stamp = stampedLock.readLock();try{System.out.println("从乐观读 升级为 悲观读");result = number;System.out.println("从新悲观读后result="+result);}finally {stampedLock.unlockRead(stamp);}}System.out.println(Thread.currentThread().getName()+"\t最后的值是"+result);}public static void main(String[] args) {StampedLockDemo demo = new StampedLockDemo();new Thread(()->{System.out.println(Thread.currentThread().getName()+"进入");demo.tryOptimisticRead();},"乐观读线程").start();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{System.out.println(Thread.currentThread().getName()+"进入");demo.write();},"写线程").start();}
}
/**
乐观读线程进入
4秒前stampedLock.validate方法值 (true无修改,false有修改)	true
乐观读线程	正在读取0秒,后stampedLock.validate方法值	true
写线程进入
写线程	 写线程准备修改。
写线程	 写线程结束修改。
乐观读线程	正在读取1秒,后stampedLock.validate方法值	false
乐观读线程	正在读取2秒,后stampedLock.validate方法值	false
乐观读线程	正在读取3秒,后stampedLock.validate方法值	false
有人修改------有写操作
从乐观读 升级为 悲观读
从新悲观读后result=50
乐观读线程	最后的值是50
*/

邮戳锁的缺点:

  1. StampedLock 不支持重入,没有 Re 开头
  2. StampedLock 的悲观读锁和写作都不支持条件变量
  3. 使用StampedLock一定不要调用中断操作

相关文章:

JUC并发编程19 | 读写锁

有一些关于锁的面试题&#xff1a; 你知道 Java 里面有哪些锁&#xff1f;读写锁的饥饿问题是什么&#xff1f;有没有比读写锁更快的锁&#xff1f;StampedLock知道嘛&#xff1f;&#xff08;邮戳锁/票据锁&#xff09;ReentrantReadWriteLock 有锁降级机制&#xff1f; Ree…...

springboot_maven项目怎么引入mybatis

在pom.xml文件中添加mybatis和mybatis-spring-boot-starter的依赖 org.mybatis mybatis ${mybatis.version} org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.spring.version} 配置mybatis 在application.properties&#xff08;或application.yml&#xff0…...

JAVA8的新特性——lambda表达式

JAVA8的新特性——lambda表达式 此处&#xff0c;我们首先对于Java8的一些特性作为一个简单介绍 Java 8是Java编程语言的一个重要版本&#xff0c;于2014年发布。Java 8引入了许多新特性和改进&#xff0c;以提高开发效率和性能。以下是Java 8的一些主要新特性&#xff1a; Lam…...

算法修炼之练气篇——练气六层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 前言&#xff1a;每天练习五道题&#xff0c;炼气篇大概会练习200道题左右&#xff0c;题目有C语言网上的题&#xff0c;也有洛谷上面的题&#xff0c;题目简单适合新手入门。&#xff08;代码都是命运之光自己写的…...

利用GPU并行计算beta-NTI,大幅减少群落构建计算时间

1 先说效果 18个样本&#xff0c;抽平到8500条序列&#xff0c;4344个OTUs&#xff0c;计算beta-NTI共花费时间如下。如果更好的显卡&#xff0c;更大的数据量&#xff0c;节约的时间应该更加可观。 GPU&#xff08;GTX1050&#xff09;&#xff1a;1分20秒 iCAMP包 的bNTIn.p(…...

Shiro框架漏洞分析与复现

Shiro简介 Apache Shiro是一款开源安全框架&#xff0c;提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用&#xff0c;同时也能提供健壮的安全性&#xff0c;可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。 1、Shiro反序列…...

(数字图像处理MATLAB+Python)第七章图像锐化-第一、二节:图像锐化概述和微分算子

文章目录 一&#xff1a;图像边缘分析二&#xff1a;一阶微分算子&#xff08;1&#xff09;梯度算子A&#xff1a;定义B&#xff1a;边缘检测C&#xff1a;示例D&#xff1a;程序 &#xff08;2&#xff09;Robert算子A&#xff1a;定义B&#xff1a;示例C&#xff1a;程序 &a…...

C# | 内存池

内存池 文章目录 内存池前言什么是内存池内存池的优点内存池的缺点 实现思路示例代码结束语 前言 在上一篇文章中&#xff0c;我们介绍了对象池的概念和实现方式。对象池通过重复利用对象&#xff0c;避免了频繁地创建和销毁对象&#xff0c;提高了系统的性能和稳定性。 今天我…...

程序设计入门——C语言2023年5月10日

程序设计入门——C语言 1、window下安装gcc 课程来源&#xff1a;链接: 浙江大学 翁恺 程序设计入门——C语言 学习日期&#xff1a;2023年5月10日 1、window下安装gcc 如果想让gcc在windows下运行&#xff0c;需要将gcc&#xff0c;及对于的lib包&#xff0c;都安装到window…...

【2023华为OD笔试必会25题--C语言版】《03 单入口空闲区域》——递归、数组、DFS

本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的25道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...

Grafana安装、升级与备份(02)

一、安装Grafana软件包 Grafana部署非常简单,直接使用yum命令从官网拉到安装再启动就可以了,本次使用的grafana版本为9.5.0 官网下载地址:Download Grafana | Grafana Labs # wget yum install -y https://dl.grafana.com/oss/release/grafana-9.5.0-1.x86_64.rpm # yum …...

【2023华为OD笔试必会25题--C语言版】《10 相同数字的积木游戏》——数组

本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的25道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...

awk命令编辑

awk工作原理 逐行读取文本&#xff0c;默认以空格或tab键分隔符进行分隔&#xff0c;将分隔所得的各个字段保存到内建变量中&#xff0c;并按模式或者条件执行编辑命令。 sed命令常用于一整行的处理&#xff0c;而awk比较倾向于将一行分成多个“字段”然后再进行处理。awk信息…...

Pinia和Vuex的区别

Pinia和Vuex都是Vue.js状态管理库 Pinia是一个轻量级的状态管理库&#xff0c;它专注于提供一个简单的API来管理应用程序的状态。 相比之下&#xff0c;Vuex是一个更完整的状态管理库&#xff0c;它提供了更多的功能&#xff0c;比如模块化、插件和严格模式等。 Pinia是基于V…...

《C++高并发服务器笔记——第四章Linux网络编程》

计算机网络等相关知识可以去小林coding进行巩固&#xff08;点击前往&#xff09; 《C高并发服务器笔记——第四章》 4.1、网络结构模式1.C/S结构①C/S结构简介②C/S结构优点③C/S结构缺点 2.B/S结构①B/S结构简介②B/S结构优点③B/S结构缺点 4.2和4.3、MAC地址、IP地址、端口…...

NFS服务器搭建(案例)

目录标题 第一个问题1.安装软件包2.进入配置文件进行定义&#xff0c;并创建对应的资源文件3.客户端进行挂载&#xff0c;并查看挂载信息&#xff0c;修改挂载权限4.客户端查看挂载的信息 第二个问题1.服务端配置文件进行定义&#xff0c;并创建对应资源文件2.客户端进行挂载3.…...

ubuntu 22.04 安装 Docker Desktop 及docker介绍

目录 一、Docker Desktop 安装 1、我们先去官网下载安装包 2、Install Docker Desktop on Ubuntu 3、Launch Docker Desktop 二、Docker 介绍 什么是docker 如何使用docker docker是如何工作的 docker build docker run docker pull 一、Docker Desktop 安装 1、我们先…...

微前端中的应用隔离是什么,一般是怎么实现的?

微前端中的应用隔离是什么&#xff0c;一般是怎么实现的? 前言一、iframe 隔离二、Web Components三、JavaScript 沙箱隔离四、Shadow DOM 隔离总结 前言 微前端中的应用隔离是指将不同的微前端应用程序隔离开来&#xff0c;以确保它们之间不会相互影响或干扰。这种隔离可以通…...

【python pandas】合并文件并剔除重复数据

1.背景 工作中需要处理多个文件&#xff0c;每个文件里面有重复的数据&#xff0c;剔除重复数据&#xff0c;保留最新的数据 2.代码&#xff1a; import pandas as pd import osdl [] #person_list是文件路径 for i in range(person_list_len):#把文件df全部集合进列表dldl.a…...

Spellman高压电源X射线发生器维修XRB160PN480X4593

spellman高压发生器维修VMX40P5X4629&#xff1b;Spellman X射线发生器维修X4593系列 X射线源维修。 Spellman所拥有的变频器架构可以使高压电源获得高利用率的效率和功率密度。固体密封的高压模块进一步减少了尺寸和重量。 基于表面贴装控制电路的数字信号处理器提供通讯接口…...

msvcr120.dll丢失怎样修复?msvcr120.dll丢失修复的四个方法

打开软件跟游戏提示msvcr120.dll丢失&#xff0c;无法执行此代码怎么办&#xff1f;刚刚遇到这个问题&#xff0c;我都无从下手。家人们&#xff0c;你是不是也被这个问题也困扰过。msvcr120.dll是什么文件呢&#xff1f;经过我一个下午的时间研究&#xff0c;终于搞清楚了&…...

马哈鱼SQLFLow数据流生成介绍

马哈鱼数据血缘分析器是当前最流行的数据血缘关系(data lineage)管理工具之一&#xff0c;它是一种通过分析SQL脚本来自动发现数据流向的工具。它通过生成一个简洁的图表来显示数据仓库中表/视图和列之间的数据流。支持超过20种流行的数据库&#xff0c;包括 bigquery, couchba…...

使用 MVC 模式,实现简单登录功能 (Kotlin)

先放效果图&#xff1a; 第一张是登录页面效果图。用户输入登录名和密码&#xff0c;经过后台的非空验证和固定值验证&#xff0c;跳转到首页 第二张是首页效果图。用户点击 “update” 显示用户名和密码 这里的用户名和密码是后台设置的固定值&#xff0c;整体的登录逻辑特别…...

ASEMI代理LT8471IFE#PBF原装ADI车规级LT8471IFE#PBF

编辑&#xff1a;ll ASEMI代理LT8471IFE#PBF原装ADI车规级LT8471IFE#PBF 型号&#xff1a;LT8471IFE#PBF 品牌&#xff1a;ADI/亚德诺 封装&#xff1a;TSSOP-20 批号&#xff1a;2023 引脚数量&#xff1a;20 工作温度&#xff1a;-40C~125C 安装类型&#xff1a;表面…...

8. 100ASK_V853-PRO开发板支持MPP媒体处理平台

0.前言 ​ MPP 系统控制模块&#xff0c;根据芯片特性&#xff0c;完成硬件各个部件的复位、基本初始化工作&#xff0c;同时负责完成 MPP&#xff08;Media Process Platform 媒体处理平台&#xff09;系统各个业务模块的初始化、去初始化以及管理 MPP 系统各个业务模块的工作…...

CLMP证书:让你在职场中脱颖而出的秘密武器!

CLMP证书是一种精益管理专业证书&#xff0c;是针对精益管理领域的专业人士和学生的培训项目&#xff0c;旨在提高他们在精益管理方面的技能和知识。那么&#xff0c;CLMP证书的含金量高吗&#xff1f;接下来我们来探讨一下。 CLMP证书的优势体现 首先&#xff0c;CLMP证书的…...

【从零开始】Docker Desktop:听说你小子要玩我

前言 &#x1f34a;缘由 捡起遗忘的Docker知识 由于本狗近期项目紧任务重&#xff0c;高强度的搬砖导致摸鱼时间下降。在上线项目时&#xff0c;看到运维大神一系列骚操作&#xff0c;dockerk8s的知识如过眼云烟&#xff0c;忘得干净的很。所以想重新恶补一下docker知识&…...

制造业为什么要数字化?

制造业数字化&#xff0c;主要包含以下一些因素&#xff0c;有优势也有缺点&#xff1a; 制造业数字化的优势&#xff1a; 提高效率&#xff1a;数字化允许各种制造过程自动化&#xff0c;可以提高效率并降低成本。可以缩短生产时间、减少浪费并提高生产率。 增强质量控制&am…...

NPC 也有了生命?当 ChatGPT 注入游戏你能想象吗

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; 目录 引言&#xff1a;西部世界元宇宙&#xff0c;还记得吗ChatGPT 的世界&#xff1f; 下图就是一个 ChatGPT 小镇&#xff1a; 引言&#xff1a;西部世界 《西部世界》以一个虚构的游戏般的“西部世界”为背景…...

Shell编程入门讲解

一.简介 Shell 是一个用 C 语言编写的命令行解释器&#xff0c;它是用户使用 Linux 的桥梁&#xff0c;它接受应用程序/用户命令&#xff0c;然后调用操作系统内核。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言。Shell 是指一种应用程序&#xff0c;这个应用程序提…...