自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(50)
  • 收藏
  • 关注

原创 UDP报文结构和注意事项

CRC算法 这个算法将每个字节的数据加起来进行比较,来判断数据是否正确。在发生bit反转后加和数据就会发生改变,从而判断数据是否正确。udp由报头和载荷组成,报头由四部分组成 源端口 目的端口 udp长度 检验和,每部分由两个字节组成。定长 不论数据多长,md5过后都是一个固定的长度 16/32/64版本。udp长度表示了该数据报的大小,一个udp数据报为64kb。分散 原始数据改变一点md5的值就会发生很大的改变。源端口和目的端口分别表示发送方和接收方的位置。检验和用来检验所得到的数据是否正确。

2024-02-13 23:25:16 764 2

原创 JAVAEE---多线程(进阶)

这也是它乐观锁的体现。乐观/悲观是在加锁前的预估,而轻量级/重量级是在加锁后对性能进行的评估。乐观锁:在加锁之前预估锁冲突发生的概率较小,在加锁的过程中所做的工作较少。悲观锁:在加锁前预估所冲突发生的概率大,所以在加锁过程中所做的工作较多。而我们所使用的synchronized加锁这是可自适锁,它可以自己判断来决定是乐观锁还是悲观锁。可重入:一把锁在一个线程里面进行了连续两次的加锁,可以加为可重入锁。它的原理其实就是解决了之前我们内存中的值和寄存器的值不同的问题。重量级锁:加锁开销大,加锁速度慢。

2023-12-11 08:30:00 115

原创 JAVAEE---synchronized

当有其他锁进行加锁,偏向锁就会立马加锁,变为轻量级锁,其他加锁就会等待。当一个线程对一个对象进行加锁,这个对象处于未加锁状态时,会进行一个标记并未真正加锁。当锁竞争加剧,轻量级锁占用的cpu就过高,就会升级为重量级锁。这里的等待策略就是挂起等待锁。编译器在进行优化时会把一些没有必要加锁但代码加了锁的地方删除。但是这里的优化是比较保守的。将细粒度的锁进行合并为一个粗粒度的锁,减少锁竞争带来的开销。synchronized的锁机制。轻量级锁/重量级锁可自适。自旋锁/挂起等待锁可自适。乐观锁/悲观锁可自适。

2023-12-08 13:29:03 108

原创 JAVAEE---多线程

这里主要的方法有newFixedThreadPool(int n)这个方法代表创建的线程数目是固定的。这里我们用一个优先级队列来存放我们要执行的任务,在构造方法中有一个线程来执行队列中的代码,而队列里面存放的元素包含两个内容,执行的内容和执行的时间。我们为了解决进程开销过大引入了轻量级进程,也就是线程,但是线程数目过多也会影响速度,所以我们又有两种解决方法。DiscardPolicy:丢弃新的线程(和第二个区别于这个新的线程不干),执行旧的线程。keepAliveTime:非必要线程最多空闲下来的时间。

2023-12-08 08:45:00 115

原创 JAVAEE---多线程

正常执行时1,2,3 没有问题,但编译器优化后可能就是1,3,2 这就有问题了。我们两个线程,一个执行到第3步,地址已经给了,但里面没有东西,全是0值,这时候另一个线程进去发现不为空,就直接返回了这个地址,但里面东西还等着初始化呀!其实我在解耦合那已经提过了,就是当我们引入一个阻塞队列/消息队列的时候就可以让b,c按照原来的速度进行运算,以为a的抗压能力要比b/c强很多的。两者都可按时间休眠。但一般情况下,wait等待时间是兜底的,一般到时间前唤醒,sleep一般会到等待时间,直接唤醒是不正常操作。

2023-12-03 09:00:00 84 1

原创 JAVAEE---多线程线程安全

上面这段代码可以正常打印出hello,按照我们前面所学,第一次加锁之后,第二次加锁应该有所冲突啊。在synchronized中,第一次加锁会记录线程和计数器为一,下次加锁会判断是否为一个线程。因为我们在循环中,不断地执行取fag和判断是否等于0的操作,jvm在优化过程中,进行了误判,后面的读取并不是读内存的fag而是寄存器/缓存中的fag。这个代码当我们输入非0的时候,按理说应该结束t1线程但实际并没有。volatile有俩个功能,保证内存可见性,禁止指令重排序。这个给也会成为死锁。1.一个线程,一把锁。

2023-11-29 17:01:09 88 1

原创 JAVAEE---多线程

add方法是对对象加锁,this代表引用add1是对类对象进行加锁,由于类对象只有一个也是成立的。addm是直接在非静态方法前面加synchronized,就是对add的一个替换,同样addm1是在静态方法前加synchronized是对add1的替换。我们对对象就进行了加锁,当t1已经加锁后,t2要想加锁就发生了锁竞争。为了解决这样的问题我们可以对count++进行打包,我们知道count++本质上应该是由三个指令完成,我们可以对其打包。这段代码执行结果就就是一个不确定的数,就存在线程安全问题。

2023-11-26 12:24:38 117 1

原创 JAVAEE---多线程

首先看一些我们将一个任务分成两个线程来执行,时间很明显有了缩短,但是发现答案不一样了,这里的原因就在于,线程安全问题,我们后面再来谈这个话题。原因很简单就是我们,在加的时候是多个指令完成的,所以存在t1取出的l,在他没有返回的时候,t2也取出来了,在放回的时候就存在问题。刚才我们执行的两次结果不同的代码就存在线程安全问题。第二个和第三个都是等待有期限,超过了这个时间我就不等了,两个就是精度存在差异。这里出现了是哪个join方法,第一个叫做死等,就是线程不结束我就一直等。BLOCKED 阻塞 锁竞争。

2023-11-25 20:34:56 107

原创 JAVAEE---多线程

我们上述是将isQuit放在成员变量中如果放在main方法中当临时变量肯定是不行的,因为lambda表达式,有一个变量捕获,要求是不变的,但我们需要改变所以不可以,但放在外面为什么可以,这就是内部类访问外部类了。start和run的区别:其实这两个是完全不相干的两个方法,start是创建新的线程分一条执行流来执行,而直接调run方法的话。还是在调用线程中执行。线程状态,emmm后面再说吧,反正他start调用前是一个状态,只有在那个状态下才可以start,start之后是另一个状态,那个状态就不能调用。

2023-11-25 18:38:06 142 9

原创 JAVAEE---多线程

因为当我们创建t线程的时侯,主线程继续向下执行,我们说这两个线程在一个进程中,但是创建线程虽然不要开辟空间,但是也不是完全没有消耗,他要建立自己的pcd。当我们运行代码的时候发现Thread和main同时打印,这就是两个线程并发执行,在上面的工具中我们也看到了main,Thread-0这俩个线程,其他一些线程都是自带的,用来完成内存回收啊,一些操作我们不用过多理解。第一个打印为false,但t已经实例过了,第二次为true因为线程没有结束,第三次为false但t仍然没有被释放,不过其线程已经结束。

2023-11-21 23:35:32 104 9

原创 JAVAEE---计算机是如何组成的

进程包含线程,每个线程是一条独立的执行流,可以单独对cpu进行调度所以状态,上下文,等都是每个线程由自己的一份。并发:其中包含并发和并行,并发是分时复用,描述一个核心上的变化,并行是多个核心同时执行,不过我们一般统称并发。你可能会发现自己的电脑,物理核心和逻辑核心不是二倍的关系,这是因为大小核技术,大核代表两个逻辑核心,小核就是一个。进程之间独立运行,互补干扰,但有时我们需要它们的数据进行交互,这就谈到了进程间通信,例如:文件,网络。首先指令是在内存中的,cpu从内存中不断获取指令,解析,执行。

2023-11-19 13:43:44 145 8

原创 MYSQL---基础篇

- (1)比较运算符 (2)BETWEEN ... AND ... (3)IN (4)IS NULL (5)LIKE (6)AND (7)OR。insert into 表(字段1, ..., 字段N) values。-- 如果存在 stu_test 表,则删除 stu_test 表。select 字段1 别名1, 字段2 别名2 from 表。select 字段1+100,字段2+字段3 from 表。select 字段1,字段2... from 表。5.删除表:-- 删除 stu_test 表。

2023-11-10 21:37:48 1120 16

原创 数据结构---HashMap和HashSet

set代表只存入一个key值,但在实际源码中,set的底层其实也是靠map来实现的。set只能存入数据一次,当第二次插入时,若哈希桶中存在元素则返回false。像这样,一个数组数组的每个节点带着一个链表,数据就存放在链表结点当中。哈希桶插入/删除/查找节点的时间复杂度是O(1)map代表存入一个key值,一个val值。map可多次存储,当第二次插入时,会更新val值。HashMap和HashSet都是存储在哈希桶之中,我们可以先了解一些哈希桶是什么。

2023-10-21 18:19:41 381 14

原创 数据结构---二叉树

设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点;孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点;

2023-10-14 15:58:08 329 17

原创 数据结构---栈和队列

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(FirstIn First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈。顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

2023-09-23 15:57:39 448 16

原创 JAVASE---认识异常

2. Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表:StackOverflowError和OutOfMemoryError,一旦发生回力乏术。Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我们实际情况的异常结构。异常的捕获,也就是异常的具体处理方式,主要有两种:异常声明throws 以及 try-catch捕获处理。java中不同类型的异常,都有与其对应的类来进行描述。

2023-09-20 18:57:29 295 18

原创 JAVASE---String类

在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了String类。

2023-09-16 18:28:25 225 19

原创 JAVASE---抽象类和接口

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

2023-09-10 17:49:46 375 17

原创 JAVASE---数组的定义与使用

数组是具有相同类型元素的集合,在内存中连续存储。1. 数组中存放的元素其类型相同2. 数组的空间是连在一起的3. 每个空间有自己的编号,起始位置的编号为0,即数组的下标。

2023-08-16 19:28:40 641 15

原创 JAVASE---方法的使用

/ 方法定义修饰符 返回值类型 方法名称([参数类型 形参 ...]){方法体代码;[return 返回值];

2023-08-08 11:55:22 168 15

原创 JAVASE---逻辑控制

顺序结构比较简单,按照代码书写的顺序一行一行执行。

2023-08-04 17:22:14 143 20

原创 JAVASE---继承和多态

比如,狗和猫,它们都是一个动物,有共同的特征,我们就可以把这种特征抽取出来。像这样把相同的可以重新放到一个类里面,进行调用,这就是继承。继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。在Java中如果要表示类之间的继承关系,需要借助extends关键字。

2023-08-03 19:33:26 341 13

原创 JAVASE---类和对象

面相对象程序设计关注的是对象,而对象是现实生活中的实体,比如:洗衣机。但是洗衣机计算机并不认识,需要开发人员告诉给计算机什么是洗衣机。上图左侧就是对洗衣机简单的描述,该过程称为对洗衣机对象(实体)进行抽象(对一个复杂事物的重新认知),但是这些简化的抽象结果计算机也不能识别,开发人员可以采用某种面相对象的编程语言来进行描述,比如:Java语言。// 创建类field;// 字段(属性) 或者 成员变量method;// 行为 或者 成员方法。

2023-07-31 16:36:35 391 17

原创 JAVASE---运算符

Java 中数据存储的最小单位是字节,而数据操作的最小单位是比特位. 字节是最小的存储单位,每个字节是由8个二进制比特位组成的,多个字节组合在一起可以表示各种不同的数据。两个表达式都为真,结果才是真,只要有一个是假,结果就是假。如果混合使用,【前置++】先+1,然后使用变量+1之后的值,【后置++】先使用变量原来的值,表达式结束时给变量+1。移位运算符有三个: > >>> ,都是二元运算符,且都是按照二进制比特位来运算的。当 表达式1 的值为 false 时, 整个表达式的值为 表达式3 的值.

2023-07-30 20:49:56 202 12

原创 JAVASE---数据类型与变量

2. Java 的 boolean 类型和 int 不能相互转换, 不存在 1 表示 true, 0 表示 false 这样的用法.1. 字符串常量:由""括起来的,比如“12345”、“hello”、“你好”。常量即程序运行期间,固定不变的量称为常量,比如:一个礼拜七天,一年12个月等。2. 整形常量:程序中直接写的数字(注意没有小数点),比如:100、1000。4. 字符常量:由 单引号 括起来的当个字符,比如:‘A’、‘1’3. 浮点数常量:程序中直接写的小数,比如:3.14、0.49。

2023-07-29 23:06:54 417 6

原创 JAVASE---认识JAVASE

随着1995年代互联网的发展,Sun公司看见Oak在互联网上应用的前景,于是改造了Oak,于1995年5月以Java的名称正式发布,并提出“Write once, Run anywhere" 的口号。注意:在运行Java程序前,必须先安装好JDK(Java Development Kit即Java开发工具包),JDK里面就包含了javac和java工具,Java程序最终是在JVM(Java虚拟机)中运行的。注意:标识符不能以数字开头,也不能是关键字,且严格区分大小写。Java的main方法。

2023-07-28 23:29:26 725 6

原创 数据结构:复杂度,顺序表

而在实际中,只需算出大概的次数,那么这里我们使用大O的渐进表示法。这就是取级数最高的即可。空间复杂度:额外占用内存的大小,注意类似斐波那契数列这种,考虑深度,而不是一共调用多少次,这和二叉树的遍历相似,我们后面会说。这是动态顺序表的所有操作,静态顺序表在这里我就不赘述了,动态顺序表的有点很明显,它不会表满,因为当它满的时候会动态开辟空间。看一个算法的好坏用的就是复杂度,而它又有两个时间复杂度和空间复杂度。今天开始学习数据结构,数据结构是计算机的核心课程之一,非常重要。复杂度比较简单,我简单说一下。

2023-07-25 10:42:06 141 6

原创 c生万物之程序环境和预处理

每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。组成一个程序的每个源文件通过编译过程分别转化成目标文件。预处理之后产生的结果在.i文件中。#define定义标识符。定义宏的时候不要吝啬括号。编译完成后在.s文件中。汇编完成后在.o文件中。#define定义宏。

2023-07-17 11:44:01 58 2

原创 c生万物之文件操作

打开文件的同时会有一FILE*的指针指向该文件,相当于建立指针和文件之间的关系。缓冲文件系统中,关键概念时“文件类型指针”,简称“文件指针”,取名FILE。牢记:在文件读取过程中,不能使用feof函数的返回值直接判断文件是否结束。数据文件:文件的内容不一定是程序,而是程序运行时读写的数据。根据数据的组织形式,数据文件被称为文本文件或二进制文件。文件在读写之前应该打开文件,读写之后应该关闭文件。首先我们要知道什么是文件:磁盘上的文件时文件。程序文件.c,.obj,.exe。文本文件和二进制文件。

2023-07-17 10:18:51 57

原创 c生万物之动态内存管理

ptr是要调整的内存地址,size是调整之后的新大小,返回跳整之后的新地址,会将原来内存中的数据移动到新的空间。为num个大小为size的元素开辟一块空间,并将空间每个字节初始化为0,这也是与malloc的区别。当有时候我们需要的空间大小在程序运行时才能知道,那么数组编译时开辟空间的方式就不能满足了。如果开辟失败,返回NULL指针,如果size为0,这个函数未定义,取决于编译器。如果ptr指的空间不是动态开辟的,那free函数的行为未定义。这个函数会申请一块连续可用的空间,并返回指向这块空间的指针。

2023-07-16 14:27:29 53

原创 c生万物之进阶指针(函数指针)

当大家运行这段代码的时候会发现两个地址相同,没错对于函数而言,函数名和&函数名是相同的概念,函数指针类型为 void(*pfun)()。函数指针数组是一个数组,数组内存放的类型是指针,而指针又指向函数。函数指针顾名思义是指向函数的指针,函数也有自己的地址。听着挺拗口,但其实就是对刚才的加一个指针而已。指向函数指针数组的指针。

2023-07-16 09:32:00 54 4

原创 c生万物之结构体,枚举,联合

大家在这里可能感觉这和数组怎么有点像,它们最大的区别就在于结构体的每个成员可以是不同类型的变量。很显然下面一种方法明显较优,因为上面调用是在结构体里面存结构体,而且它的大小无法计算,而下面的方法则是利用指针,使内存变为定值。大家可以在自己的编译器看到这个结构体的大小是12,这就是内存对齐了,接下来问我说一下内存对齐的规则。这就是位段,位段的成员必须是整型家族的,开辟空间是按需要四个字节或一个字节开辟的。括号中数字是多少,默认对齐数就是多少,不填的时候就是默认对齐数。3.结构体的整体大小为对齐数的整数倍。

2023-07-15 10:22:28 42 3

原创 c生万物之字符函数和字符串函数的实现与模拟

这个函数是判断两个字符串是否相等,判断字符串是否相等,是比较其ASCII值的大小。该字符串的作用是求字符串中元素个数,以'\0'作为结束标志,计算时不包括'\0',返回值size_t是无符号的。追加函数,在字符串一后面加一个字符串二。要保证字符串一给的空间足够大,字符串二追加以'\0'结束。同样以'\0'结束,是将字符串二拷贝给字符串一,这里要注意要求,目标空间足够大。这是对其的模拟实现,第一个使用计数器方法,第二个没有用计数器,第三个使用指针。字符串找字符串,对字符串进行模式匹配,在多次判断。

2023-07-11 18:30:58 45 2

原创 c生万物之指针进阶(指针数组及数组指针)

但是这样的代码我们一般不会使用,真正使用数组指针的是二维数组,我们知道二维数组的每一个元素可以看作一个一维数组,这里用数组指针接收那么,每一个指针都指向了二维数组中的一个以为数组。这是上面一段代码运行的结果,arr+1只加了四个字节,&arr+1加了40个字节,这是因为arr代表数组首元素的地址,而&arr代表整个数组的地址。这就是一个数组指针,因为p先和*结合,说明p是一个指针变量,指向一个大小为10个整形的数组。指针数组是一个数组,与普通数组不同的是他数组内存放的类型是指针。今天主要了解数组指针。

2023-07-11 15:36:29 51 2

原创 c生万物之指针进阶(字符指针)

结果是 0 1,这是因为str1和str2分别开辟一块空间将"hello csdn"放入,所以地址不同。而str3和str4是指向内存中的"hello csdn",所以他们所存储的地址相同。断更一个月真的报意思啊,由于期末复习没有时间写,给大家道个歉。而下面的是在内存空间中开辟"hello csdn"而p内存放的是首元素h的地址。区别在于,上面的指针是将ch的地址存在指针变量p内,ch内存的是字符w。我们一般使用字符指针就像上面这样,但既然是进阶,那么还有一种方式如下。今天开始我们学习指针的进阶部分。

2023-07-09 12:12:20 51 4

原创 c生万物之浮点型在内存中的存储

这个3就是次方数,而为什么要加127呢,因为次方有负数),还有23位存放除1以外的数(还以上面的为例及存放0011在后面)这就是它存储的规则。今天我们聊一下浮点型在内存中的存储,我们知道整形在内存中存储补码,用正数来说,因为原码、反码、补码,相同所以直接存储,那浮点数的存储是什么样的呢?先看一下下面的代码。而浮点型在IEEE 754中规定,float类型,32个比特位第一位符号位,还有8为来存次方数加127,这段代码的运行结果如下,很明显浮点型的存储与整形有很大差距。下来我讲一下它的存储规则。

2023-06-03 14:59:07 53 2

原创 C生万物之扫雷

昨天写了一个三子棋的代码,今天分享一下扫雷,扫雷我们要知道,我们要有一个存放是否有雷的二维数组,和一个给用户观看的二维数组,首先对其初始化,然后布雷。排雷时,若无雷,则将此处位置改变,若有雷则失败。

2023-05-15 10:36:04 49 5

原创 C生万物之三子棋游戏

下来到了下棋的步骤,我们输入坐标落子,当此处有子时,应该提醒,下来用随机值函数实现电脑下棋,每次下完棋应该判断输赢,三子棋输赢由三种情况,行、列、对角,判断若一样则返回符号代表赢,否则要判断是否还有可以落子位置,若没有则为平局。首先下三子棋应该在一个二维的平面上完成,所以我们用一个二维数组,然后接下来棋盘初始化我们要将其全部设为空格,接着打印棋盘。先看看代码,由三个文件组成,一个头文件,一个测试源文件,一个实现源文件。

2023-05-14 16:40:06 42 1

原创 C生万物之函数递归

递归容易理解,可他的缺点在于每次调用自身都要开辟栈帧空间,造成空间浪费,那么还有一种方法叫做迭代,简单来讲迭代就是一个循环,他的好处就在于它不会一直开辟空间,不会产生栈溢出的现象。1.存在一个限制条件,当满足限制条件时递归不再继续。这就是一个简单的递归,print函数调用自身。递归:程序调用自身的编程技巧称为递归。2.每次递归后越来越接近条件。不然就会出现死递归的情况。当然递归也有其限制条件。

2023-05-10 10:13:17 52

原创 C生万物之函数(1)

自定义函数是需要我们自己编写的函数,一些需求库函数无法满足时就需要我们自己来编写,自定义函数对我们来说是更为重要的。与库函数一样的是它有函数名,参数,返回类型。这里的函数相当于一个工厂,形参相当于所需原料,实参相当于原料。调用这个函数相当于进行一次加工。库函数是计算机中自带的一些函数,例如scanf函数printf函数都是库函数。与数学中相似,在维基百科中对函数定义为:子程序。形参 函数体内的参数,不是实际存在的。函数又分为库函数和自定义函数。实参 真实的参数,实际存在。

2023-04-26 14:57:45 56 1

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除