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

多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile

一、回顾💛

谈谈volatile关键字用法

volatile能够保证内存可见性,会强制从主内存中读取数据,此时如果其他线程修改被volatile修饰的变量,可以第一时间读取到最新的值。

二、💙 

HashMap线程不安全没有锁,HashTable线程更加安全,关键方法都提供了synchronized,CocurrrentHashMap是线程安全的hash表

HashMap是在方法中直接加上synchronized,就相当于针对this(当前对象)加锁,

HashTable——全局锁,会安全,但是缺点就是有巨大的锁开销,会形成阻塞等待

HashTable<String,String>ht=......;

hs.set("aaa","111")

任意的针对ht对象的操作,都会涉及针对this的加锁,此时如果多个线程想操作ht,就一定会触发激烈的锁竞争,最后都只能一个一个排着队,依次执行——并发

所以会出现CocurrentHashMap

我们学过的哈希表的二次探测,真实hash表基本不会出现,而是采用链表的方式(哈希桶),如果修改操作是像下图这样,针对两个不同的链表进行修改,是否存在线程安全问题->当然不会

 但是假如说是扩容,就可能会有影响了,但是扩容是很有重量级的操作,把整个的哈希表都需要重新搬运一遍,这样锁的开销也就微乎其微。

那么有人也会问-假如上面那种是不是说明这种我就完全不需要加锁了,反正也是没有线程安全问题,但是也不行,因为下图这种,假如说去插入两个在同一个链表的位置,又会涉及到线程的安全问题——解决方法每个链表都安排一把锁-这样开销就会小很多,这样第二个操作就会陷入阻塞等待,因为第一个正在修改,这样这个问题就解除了。

 一个hash表上链表个数这么多,两个线程正好在同时修改一个链表的操作本身就概率比较低,整体锁的开销大大降低了,这么修改也就不会有这么多的线程阻塞。

此时可能此时有人问,该怎么给每个线程加锁呢——由于synchronized随意对象都可以加锁,所以可以简单使用每个链表的头节点使用。

这也就是我们的改进

1.ConcurrentHashMap减小了锁的粒度,每个链表有一把锁,大部分情况下都没有涉及锁冲突。

2.广泛使用了CAS操作,size++,这样的操作也不会存在锁冲突

3.写操作进行了加锁(链表级)读操作,不加锁了就——如果有一个线程读,一个线程写会有问题吗,最多就是修改的一瞬间,读到一个旧版本/新版本的数据,不确定而已,通过一些精密的操作,保证不会读“半个数据”(有新有旧)

4.针对扩容操作进行优化,渐进式扩容

HashTable一旦触发扩容,就会一口气完成所有元素的搬运,这个过程非常耗时间,我们的大部分请求会很顺畅,但是突然一个请求会卡很久——而且并不好确认哪里的问题,因为这个触发概率很小,很气。

所以这个改进——化整为零,当需要扩容时,创建一个更大的数据,然后把旧的数据逐渐往新的数据哈桑搬运,会出现一段时间——新,旧数组共同存在的时间——

1.新增数据,就往新数组上插入

2.删除数据,把旧的数组上的数据删除掉即可

3.查找元素,新旧数据都要查

4.修改元素,统一把这个元素放到新的数组上

与此同时,每个操作都会触发一定到搬运,每搬运一次,就可以保证整体时间不是很大,积少成多之后,逐渐完成搬运了,也就可以把之前的旧的数组销毁了

上面说的是HashTable和ConcurrentHashMap的区别

HashMap和ConcurrentHashMap的区别,就是线程安全和不安全的区别。

treeMap和hashMap区别——哈希表和红黑树之间的区别

面试有可能问一手

ConcurrentHashMap的分段锁

Java8之前,ConcurrentHashMap的分段锁区别

Java8之后就没有分段锁了

ConcurrentHashMap的分段锁确实可以提高效率,但是不如一个链表一把锁效率更高,而且分段锁的维护更加麻烦。

三、 💜

文件IO操作

文件->存储数据的方式

操作系统通过“文件系统”这样的模块来管理硬盘。

文件~不同的文件系统,管理文件的方式都是一致的

通过“目录”构成了N叉树的文件结构

如D盘->tmp->cat.jpg通过这个路线就可以找到确定电脑的唯一一个文件,这个路线就叫做路径。

以盘符开头的路径,也叫做绝对路径,绝对路径是从电脑这里出发找文件的过程。

以···或···开头的路径,叫做绝对路径,相对路径,需要有一个基准目录/工作目录,表示从这个基准目录出发怎么才能找到这个文件

如以D:为基准目录

.白哦是当前所在目录

./tmp/cat.jpg

以D:/tmp为基准

./cat.jpg

..表示当前目录的上一层目录

如果D:/tmp/111为基准(是以tmp开始查找)

../cat.jpg    

D:/tmp/111/aaa为基准 

../../cat.jpg(也是以tmp开始查找)

文件系统存储的文件具体分为两个大类:

1.文本文件

utf8就是一个大表(实际上)表上数据的集合叫做字符。

2.二进制文件

二进制数据

如何区分呢?

一个最简单的方式判断就是:文件是二进制还是文本,直接使用记事本打开,如果打开之后能看懂,就是文本文件,假如看不懂,就是二进制文件,记事本打开文件,就会尝试把当前数据在码表中查询~

word文档就是二进制文件(功能太多了,属于是“富文本”需要用二进制去组织),后续文本的操作,文本和二进制操作方式完全相同的

文件系统的操作——

1.创建文件

2.删除文件

3.创建目录

通过一个类的使用——java.io.File(IO-Input和output,站在cpu的角度,来看待输入输出。)

通过File对象描述一个具体的文件,File对象可对应一个真实的文件,也可对应一个不存在的文件。

File(String pathname)此处参数字符串表示一个路径,可以是绝对路径,也可以是相对路径

 站在操作系统的角度来看,目录也是文件,操作系统中的文件是更为广义的概念,具体里面有很多种不同的类型

1.普通文件(通常见到的文件)

2.目录文件(通常见到的文件夹)<-(高级,文件夹太土鳖的)

1.File file=new File("./test.txt");             //路径随意填写(可以不存在)

2.file.createNewFile()//创建文件(有可能抛异常)

3.file.delete(删除掉文件)

file.deleteOnExit(),(这个是程序退出后再删除,不是立刻删除)有的时候,可能会有这样一个功能,临时文件程序运行的时候,搞一个临时文件,程序结束了,临时文件会自动进行删除。

像是office等生产力软件,都有生产临时文件功能,这个临时文件就自动存储了你当前的编辑状态,如果有人word长期不保存,突然断电关机,此时你在进行重启,由于刚才是非正常关闭,临时文件来不及删除是仍然存在的,office启动就能知道上次是异常关闭,就会提醒你是否要从之前的临时文件恢复未保存的结果。

 创建一个目录,

import java.io.File;
import java.io.IOException;public class Demo11 {public static void main(String[] args) throws IOException {File file=new File("./d.txt");//创建文件// file.createNewFile();//删除掉文件//  file.deleteOnExit();//创建一层目录mk->make,dir->directory//mkdir()一次只能创建一级目录file.mkdir();//  mddirs能创建多极目录file.mkdirs();}
}

 ​​

文件命名,也可以起到文件移动的效果

以上文件系统操作,都是基于File类完成的。

文件流stream-主要原因,操作系统流

文件内容的操作核心步骤,四个

1.打开文件 fopen                            

2.关闭文件 fclose

3.读文件     fread

4.写文件     fwrite

JavaIO流是庞大的体系,涉及非常多的类,不同的类有不同的特性,使用方法基本类似。

 字节流:InputStream,OutputStream ,后续的一些操作字节的类都是衍生自这两个类,以操作字节为单位(二进制文件)

字符流: Reader Write  操作字符为单位(文本文件)

reader.close:让一个进程打开一个文件,是要从系统中一定的资源(占据进程pcb文件描述符中的一个表项文件描述符是顺序表(长度有限,不可扩容),如果不释放,就会出现“文件资源泄露”这是很严重的问题,一旦一直打开文件,而不去关闭不用的文件,文件描述符就会被占用满(导致服务器宕机)后续无法打开新的文件)->年终奖消失大法

我们平时可以使用try catch finally {close}但是不够优雅

最好使用try with resources

  //这个就如同sychronized一样,自动给你关闭文件,但是这块写的不完全,需要写使用资源的操作
try(Reader reader=new FileReader("d:/test.txt"))

read()一次读一个字符<->char(按照Integer来表示,表示两个字符的范围,-1表示已经读取完毕eof了)

可能会有疑问——utf8格式一个字符三个字节,为什么读出字符是两个字节呢

java的char类型是用unicode编码的(一个字符,两个字节),使用完这个方法读取一个字符,java标准库内部会帮我们自动转换!unicode和utf8(一个字符)是不同的。

这个会把读到的内容,填充到参数cbuf是数组中,此处的参数,相当于一个“输出型参数”

char buf[]=new char[1024];

reader.read(buf)//这种写法java中不太常见(c++)使用偏多,通过read,就会把一个本来空的数组,填充上内容

read(char[]cbuf,int off,int len)

多个小文件,都需要读取且需要拼接到一起,就用这个方法,比如三个文件,大小都是100字节

read(cbuf,0,100)
read(cbuf,100,100)
read(cbuf,200,100)

我们如同下图那样,先读取txt文件,然后在去依次输出这个字符串,读到文件末尾退出

import java.io.*;public class Demo12 {public static void main(String[] args) throws IOException {try(Reader reader=new FileReader("/Users/lcl/untitled7/src/test.txt")){while(true){char buf[]=new char[1024];int n=reader.read(buf);if(n==-1){System.out.println("读到文件末尾");break;}for(int i=0;i<n;i++){System.out.println(buf[i]+",");}
//String构造方法内部,默认是utf8(但是你可以让他变成gbk
String s=new String(0,n,"gbk");String s=new String();System.out.println(s);}}}
}

read(byte[]b)->一次读若干字节,填满数组的一部分

Scanner一视同仁,只是把当前读到的字节数据进行转换~(不关心这个数据来自于标准输入,还是来自文件或者网卡)

以前学过的Scanner只是读文本文件的,不适合读二进制文件,在标准库中,还提供了一些具体工具类,辅助更方便的读写二进制文件。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;public class Demo13 {public static void main(String[] args) throws IOException {try(InputStream inputStream=new FileInputStream("/Users/lcl/untitled7/src/test.txt")){Scanner scanner=new Scanner(inputStream);
//第一段到空格之前的字符串,读取test文件读取数据String s= scanner.next();;System.out.println(s);String s1= scanner.next();;System.out.println(s1);
第二段空格之前,相当于读取一个词String s2= scanner.next();;System.out.println(s2);}}
}

输出,使用方法和输入十分相似——

关键的操作是write,write之前要打开文件,用完需要关闭文件,输出流对象(无论字节流还是字符流)会打开文件之后,清空文件内容!正如我们之前那么写的i,变成了我喜欢你

但是我们假如想在他的后面去写,而不去自动删除,该怎么做呢,可以追加写,此时就不进行清空操作。OutputStream使用方式完全一样,只不过write方法不能支持“字符串参数”。,只能按照字节或者字节数组写入。

Scanner搭配InputStream可以简化代码效果(可以不像我们之前那么一点一点读)

PrintWriter(sout,点击里面的out,她就是这个类,使用一系列方法printf,println)搭配OutputStream

经典面试题,写个代码递归目录

深度优先-DFS(先中后序,递归)

广度优先-BFS(层序)


import java.io.File;
import java.util.Scanner;public class Demo15 {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入搜索的根目录");File rootPath = new File(scanner.next());System.out.println("请输入删除的关键词");String word = scanner.next();if (!rootPath.isDirectory()) {System.out.println("路径不合法");return;}scanDir(rootPath, word);scanner.close();}public static void scanDir(File currentDir, String word) {//先列出当前目录包含哪些内容File[] files = currentDir.listFiles();if (files == null || files.length == 0) {//空目录/非法目录return;}for (File f : files) {System.out.println(f.getAbsolutePath());if (f.isFile()) {//3看当前文件是普通文件,看文件名字,是否包含word,来决定是否删除dealFile(f, word);} else {//4假如是当前文件是目录文件(文件夹)就再次递归,直到找到文件。scanDir(f, word);}}}private static void dealFile(File f, String word) {//是根据文本的是名字删除,假如不存在就返回if (!f.getName().contains(word)) {return;}//打印删除文件的路径System.out.println("要删除的文件:" + f.getAbsolutePath());f.delete();}
}

2.进行普通文件的复制,把一个文件复制成另一个文件

在这之前我们先要想一个问题,读文件一次读1024好,还是20480好?

每次read都是访问硬盘,此时把buffer(接受的数组)变大,就能降低访问硬盘次数提高效率,buffer大的前提,空间需要充足

import java.io.*;
import java.util.Scanner;public class Demo16 {public static void main(String[] args) throws IOException {System.out.println("请输入复制的文件路径");Scanner scanner = new Scanner(System.in);String src = scanner.next();File srcFile = new File(src);if (!srcFile.isFile()) {System.out.println("源文件不存在或者不是一个文件");return;}System.out.println("请输入复制目标文件路径");String dest = scanner.next();File destFile = new File(dest);//不要求目标文件本身存在,但要保证目标文件所在的目录所在。//假设目标文件写作d:/tmp/cat2.jpg,就需保证d:tmp目录所在if (!destFile.getParentFile().isDirectory()) {System.out.println("您的路径非法");return;}
//输入流,输出流,按照字节流方式去打开这个文件try (InputStream inputStream = new FileInputStream(srcFile);OutputStream outputStream = new FileOutputStream(destFile)) {while(true){byte[] buffer = new byte[1024];int n = inputStream.read(buffer);System.out.println("n=" + n);if (n == -1) {                    //读完事了System.out.println("读到eof,结束"); break;}
//从0开始,写n这么长outputStream.write(buffer, 0, n);}}}}

相关文章:

多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile

一、回顾&#x1f49b; 谈谈volatile关键字用法 volatile能够保证内存可见性&#xff0c;会强制从主内存中读取数据&#xff0c;此时如果其他线程修改被volatile修饰的变量&#xff0c;可以第一时间读取到最新的值。 二、&#x1f499; HashMap线程不安全没有锁,HashTable线程…...

专线连接交换机设置 – 如何实现高效率的网络连接?

专线链接交换机设置 – 如何实现高效率的网络连接&#xff1f; 什么是专线连接交换机&#xff1f; 在现代互联网中&#xff0c;网络连接的快速和高效是至关重要的。尤其是对于需要大量数据传输和保证网络稳定性的企业和组织来说&#xff0c;专线连接交换机是一项非常重要的技…...

C#,数值计算——Midexp的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class Midexp : Midpnt { public new double func(double x) { return funk.funk(-Math.Log(x)) / x; } public Midexp(UniVarRealValueFun funcc, double aa, d…...

微信小程序使用本地存储方法wx.setStorageSync()和wx.getStorageSync()

微信小程序的本地存储可以使用wx.setStorageSync()和wx.getStorageSync()方法实现 使用wx.setStorageSync()方法可以将数据以键值对的方式存储到本地存储中&#xff1a; wx.setStorageSync(demo, demo123);获取数据&#xff1a;使用wx.getStorageSync()方法可以从本地存储中获…...

题解:ABC317C - Remembering the Days

题解&#xff1a;ABC317C - Remembering the Days 题目 链接&#xff1a;Atcoder。 链接&#xff1a;洛谷。 难度 算法难度&#xff1a;B。 思维难度&#xff1a;B。 调码难度&#xff1a;C。 综合评价&#xff1a;普及-。 算法 深度优先搜索。 思路 先建图&#x…...

【CSS】简记CSS效果:通过transition(动画过渡属性)实现侧边栏目滑入滑出

需求 在资金明细的页面中&#xff0c;点击按钮时筛选区域从左侧滑出&#xff0c;完成筛选点击确认后调用接口完成数据查询&#xff0c;筛选区域滑入左侧&#xff1b; 基于微信小程序页面实现 wxml代码 <view><!-- 操作按钮 --><button type"primary&qu…...

LeetCode——最大子数组和(中等)

题目 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#x…...

Zookeeper集成SpringBoot

Curator 是 Apache ZooKeeper 的Java客户端库。 Zookeeper现有常见的Java API如&#xff1a;原生JavaAPI、Curator、ZkClient等。 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"…...

ModaHub魔搭社区:星环科技致力于打造更优越的向量数据库

在数字化时代,数据成为了最重要的资源之一。随着人工智能、大数据等技术的不断发展,向量数据库成为了处理这类数据的关键工具。星环科技作为一家专注于数据存储和管理技术的公司,其重要目标就是将向量数据库打造得更为优越。 在星环科技,有一个专注于向量数据库的团队。这个…...

Dubbo默认使用什么序列化框架?还有哪些?

Dubbo默认使用的序列化框架是Hessian 2.0。Hessian是一种基于二进制的序列化协议&#xff0c;它具有简单、高效的特点&#xff0c;适用于网络传输和存储数据。Hessian在Dubbo中被广泛使用&#xff0c;因为它可以在不同的编程语言之间进行对象的序列化和反序列化。 除了Hessian…...

攻防世界-What-is-this

原题 解题思路 解压后文件 没有后缀&#xff0c;不知道是什么文件。用notepad打开找不到flag。 尝试当成压缩包解压。 用stegsolve以打开图片1&#xff0c; 合成两张图片。...

[C++]构造与毁灭:深入探讨C++中四种构造函数与析构函数

个人主页&#xff1a;北海 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;C/C&#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论区留言指正&#xff0c;大家一起学习交流&#xff01;&#x1f9…...

【跟小嘉学 Rust 编程】二十一、网络编程

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...

一文了解聚合支付

第四方支付是相对于第三方支付而提出的概念&#xff0c;又被称为“聚合支付”是指通过聚合第三方支付平台、合作银行、等多种支付工具进行的综合支付服务。 简言而之&#xff0c;把支付接口聚合到一个平台上面&#xff0c;来给商家或者个人来提供支付服务。 第四方支付集中了各…...

118.杨辉三角

一、题目 118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>>data(numRows);for(int i0;i<numRows;i){data[i].resize(i1);//扩容data[i]…...

第7节——渲染列表+Key作用

一、列表渲染 我们再react中如果渲染列表&#xff0c;一般使用map方法进行渲染 import React from "react";export default class LearnJSX2 extends React.Component {state {infos: [{name: "张三",age: 18,},{name: "李四",age: 20,},{nam…...

NTP服务器时间配置

简介 ntp服务器是一个同步时间都服务器。 开启ntpd 1.查看状态&#xff08;可以看到状态为&#xff1a;inactive&#xff0c;也就是没有启动ntp服务&#xff09; [rootlocalhost]$ systemctl status ntpd ● ntpd.service - Network Time ServiceLoaded: loaded (/usr/lib/…...

vulhub之MinIO信息泄露漏洞(CVE-2023-28432)

文章目录 0x01 前言0x02 漏洞描述0x03 影响范围0x04 漏洞复现1.启动环境2.查看端口3.构造POC 0x05 修复建议 0x01 前言 本次测试仅供学习使用&#xff0c;如若非法他用&#xff0c;与本文作者无关&#xff0c;需自行负责&#xff01;&#xff01;&#xff01; 0x02 漏洞描述 …...

C语言:递归思想及实例详解

简介&#xff1a;在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。通过函数的自调用化繁为简。 递归可以说是编程中最神奇的一种算法。因为我们有时候可能不能完全明晰代码的运行过程&#xff0c;但是我们却知道代码可以跑出正确的结果。而当我们使…...

好题分享0

P2141 [NOIP2014 普及组] 珠心算测验 原题链接 : [NOIP2014 普及组] 珠心算测验 - 洛谷 思路 : 用哈希表来存出现过的两数之和&#xff0c;最后ans即可 代码 : #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define end…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制

目录 节点的功能承载层&#xff08;GATT/Adv&#xff09;局限性&#xff1a; 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能&#xff0c;如 Configuration …...