自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 工厂模式

工厂模式:实例化对象不需要使用 new,用工厂方法代替,将调用者和实现类进行解耦简单工厂模式简单工厂模式:用来生产同一等级结构的任何产品(对于新增加的产品,需要修改已有的代码)假设有一个接口汽车,有两个子类”Wuling“和”Tesila“分别实现了这个接口public interface Car { void name();}public class Tesila implements Car{ @Override public void name() {

2021-06-15 20:32:14 141

原创 生产者和消费者

假设有一个仓库,只能放一个对象,需要完成:两个线程一个生产一个消费生产者—>java.lang.Object@6865ca8a消费者—>java.lang.Object@6865ca8a生产者—>java.lang.Object@5d561924消费者—>java.lang.Object@5d561924…代码实现import java.util.ArrayList;import java.util.List;public class ThreadDemo {

2021-03-19 15:20:16 117

原创 ThreadLocal

ThreadLocal 的作用主要是做数据隔离,填充的数据只属于当前线程,变量的数据对别的线程而言是隔离的,在多线程环境下,可以防止自己的变量被其它线程篡改。Spring 采用 ThreadLocal 的方式,来保证单个线程的数据库操作使用的是同一个数据库连接。底层原理:set 的源码:public void set(T value) { Thread t = Thread.currentThread(); // 获取当前线程 ThreadLocalMap map = getMap(

2021-03-19 13:33:44 96

原创 Redis 事务

事务相关命令:MULTI:开启事务EXEC:执行事务DISCARD:取消事务,事务中的语句全部不执行WATCH:监视某些键,CAS实现乐观锁WATCH 命令的实现WATCH 命令是一个乐观锁,它可以在 EXEC 命令执行之前,监视任意数量的数据库键,并在 EXEC 命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器拒绝执行事务,并向客户端返回代表事务执行失败的空恢复。例:如果监视的数据在事务中没有使用,但是被修改了,依然会执行失败WATCH具体实现:每

2021-03-18 18:58:04 106 1

原创 装饰者模式

装饰者模式可以扩展一个类的功能或给一个类添加附加职责优点:1.不改变原有对象的情况下给一个对象扩展功能2.使用不同的组合可以实现不同的效果3.符合开闭原则装饰者模式中包含的角色1.Component 接口所以的被包装类、包装类都实现了这个接口。2.ConcreteComponent 类被包装的实现类3.Decorator 抽象类所有的包装类都继承自这个类,Decorator实现Component接口方便实现多层嵌套包装4.ConcreteDecorator 类具体的包装类,用于扩

2021-03-17 16:53:24 48

原创 单例模式

单例模式:一个类只能存在一个实例化的对象饿汉式// 饿汉式public class Hungry { private Hungry() { } private static final Hungry HUNGRY = new Hungry(); public Hungry getInstance() { return HUNGRY; }}懒汉式// 懒汉式public class Lazy { private Lazy()

2021-03-14 11:39:50 70

原创 Redis 持久化

持久化简介Redis 的数据全部存储在内存中,如果突然宕机,数据就会全部丢失,因此必须有一套机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的持久化机制,它会将内存中的数据保存到磁盘中。持久化的过程:客户端向数据库发送写命令(数据在客户端的内存中)数据库接收到客户端的写请求(数据在服务器的内存中)数据库调用系统 API 将数据写入磁盘(数据在内核缓冲区内)操作系统将写缓冲区传输到磁盘控制器(数据在磁盘缓存中)操作系统的磁盘控制器将数据写入实际的物理媒介中(数据在磁

2021-03-13 22:49:25 51

原创 volatile详解

计算机中为什么会出现线程不安全的问题计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中会涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。为了处理这个问题,在CPU里面就有了高速缓存(Cache)的概念。当程序在运行过程中,会将运算需要的数据从主存复制一份

2021-03-07 22:20:59 276 1

原创 从2-3查找树到红黑树

2-3查找树为了保证查找树的平衡性,我们需要一些灵活性,因此在这里我们允许树中的一个结点保存多个键。2-结点:含有一个键(及其对应的值)和两条链接,左链接指向的2-3树中的键都小于该结点,右链接指向的2-3树中的键都大于该结点。3-结点:含有两个键(及值对应的值)和三条链接,左链接指向的2-3树中的键都小于该结点,中链接指向的2-3树中的键都位于该结点的两个键之间,右链接指向的2-3树中的键都大于该结点。示意图:...

2021-01-26 15:04:24 105

原创 数据库事务的 ACID 特性

事务概念:事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。ACID:1. 原子性(Atomicity)事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。回滚可以用回滚日志来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。2. 一致性(Consistency)数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对一个数据的读取结果都是相同的。3. 隔离性

2021-01-24 17:06:22 2261

原创 进程和线程

进程进程是资源分配的基本单位。在操作系统中,是用进程控制块 (Process Control Block, PCB) 来描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对PCB 的操作。PCB 是进程存在的唯一标识,这意味着一个进程的存在,必然会有一个 PCB,如果进程消失了,那么 PCB 也会随之消失。PCB 具体包含什么信息呢?进程描述信息:进程标识符:标识各个进程,每个进程都有一个并且唯一的标识符;用户标识符:进程归属的用户,用户标识符主要为共享和保护服务;

2021-01-23 17:25:16 921

原创 内存管理

虚拟内存虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要

2021-01-23 16:06:24 212

原创 JVM 类加载机制

类是在运行期间第一次使用时动态加载的,而不是一次性加载所有类。因为如果一次性加载,那么会占用很多的内存。类的生命周期包括以下 7 个阶段:加载(Loading)验证(Verification)准备(Preparation)解析(Resolution)(它在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 语言的运行时绑定特性,也称为动态绑定或晚期绑定)初始化(Initialization)使用(Using)卸载(Unloading)类加载过程包含了加载、验证、准备、解

2021-01-22 16:39:27 104

原创 JVM 垃圾收集

垃圾收集主要是针对堆和方法区进行。程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收。判断一个对象是否可被回收1.引用计数算为对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。在两个对象出现循环引用的情况下,此时引用计数器永远不为 0,导致无法对它们进行回收。正是因为循环引用的存在,因此 Java 虚拟机不使用引用计数算法。public clas

2021-01-21 20:49:14 79

原创 JVM运行时数据区

运行时数据区,JDK 1.6:运行时数据区,JDK 1.8:程序计数器(PC寄存器 Program Counter Register)作用:程序计数器用来存储指向下一条指令的地址。由执行引擎读取下一条指令。特点:它是一块很小的内存空间,几乎可以忽略不记。也是运行速度最快的存储区域。每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致。任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址;如果是

2021-01-20 17:44:29 89

原创 当键入网址后,到网页显示,其间发生了什么?

键入网址到网页显示,有以下几个步骤:解析URL,生成 HTTP 请求消息DNS 域名解析将 HTTP 的传输工作交给操作系统的协议栈TCP 可靠传输IP 远程定位MAC 两点传输网卡,将数字信号转化为电信号交换机转发包路由器,转发网络包到下一个路由器或目标设备服务器接收数据,响应数据包HTTP 请求消息浏览器做的第一步工作是解析 URL ,从而生成发送给 web 服务器的请求消息。URL 里的各个元素代表的含义:所以图中的长长的 URL 实际上是请求服务器里的文件资源。如

2021-01-20 14:49:49 333

原创 IP协议

IP基本认识IP 在 TCP/IP 参考模型中处于第三层,也就是网络层。网络层的主要作用是:实现主机与主机之间的通信,也叫点对点(end to end)通信。网络层与数据链路层有什么关系呢?有的小伙伴分不清 IP(网络层) 和 MAC (数据链路层)之间的区别和关系。其实很容易区分,在上面我们知道 IP 的作用是主机之间通信中的,而 MAC 的作用则是实现「直连」的两个设备之间通信,而 IP 则负责在「没有直连」的两个网络之间进行通信传输。举个生活的栗子,我要去一个很远的地方旅行,制定了一

2021-01-19 17:10:57 302

原创 TCP重传、滑动窗口、流量控制、拥塞控制

TCP 是一个可靠传输的协议。为了实现可靠性传输,需要考虑很多事情,例如数据的破坏、丢包、重复以及分片顺序混乱等问题。如不能解决这些问题,也就无从谈起可靠传输。TCP 是通过序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现可靠性传输的。重传机制TCP 实现可靠传输的方式之一,是通过序列号与确认应答。在 TCP 中,当发送端的数据到达接收主机时,接收端主机会返回一个确认应答消息,表示已收到消息。但在错综复杂的网络,并不一定能顺利的进行正常的数据传输,万一数据在传输过程中丢失了呢?所以 T

2021-01-19 15:04:38 144

原创 TCP四次挥手

TCP四次挥手过程和状态变迁客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。客户端收到服务端的 FIN 报文

2021-01-18 17:44:01 1372

原创 冒泡排序&选择排序

冒泡排序1.思路:冒泡排序只会操作相邻的两个数据。每次冒泡排序都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩交换。2.图解:对数组[4, 5, 6, 3, 2, 1]进行冒泡排序,每次冒泡操作的详细过程如下图所示:从图中可以看出只需要array.length-1次冒泡,数组就可以排列好。3.代码实现public void bubbleSort(int[] arr) { if (arr == null || arr.length < 2) re

2021-01-10 17:45:03 181 1

原创 基数排序

// 基数排序public class RadioSort { public static void radioSort(int[] arr) { if (arr == null || arr.length < 2) return; int n = arr.length; // 找最大值 int max = arr[0]; for (int i = 1; i < n; i++) {

2021-01-10 17:37:05 100

原创 TCP三次握手

TCP建立连接TCP三次握手过程和状态迁移TCP是面向连接的协议,所以使用TCP前必须先建立连接,而建立连接是通过三次握手而进行的。一开始,客户端和服务器都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。...

2021-01-09 21:30:07 1464

原创 TCP基础

TCP首部源端口号和目标端口号:各占两个字节,分别写入源端口号和目标端口号。序号:占4个字节,TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值指的是本报文段所发送的数据的第一个字节的序号。比如,发送的报文段的序号是100,发送的数据大小位200字节,那么下一个报文段的序号应为300。用来解决网络包的乱序问题。确认号:占4个字节,指下一次期望收到的数据的序号,发送端收到这个确认应答以后可以认为在这个序号

2021-01-06 17:43:12 996 1

原创 HTTP

概念:HTTP是超文本传输协议,也就是HyperText Transfer Protocol。HTTP是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。HTTP状态码1xx:提示信息,表示目前是协议处理的中间状态,还需要后续的操作,实际用到的比较少。2xx:成功,这类状态码表示服务器成功处理了客户端的请求。200 OK:是最常见的成功状态码,表示一切正常。如果是非HEAD请求,服务器返回的响应头都会有body数据。204 No Content:也是常见的成功状

2021-01-04 15:39:26 521 1

原创 线程池

程序的运行,本质上是占用系统的资源,线程的创建、销毁十分销毁资源。优化系统资源的使用可以使用池化技术(线程池、连接池、内存池、对象池… )池化技术:事先准备好一些资源,有人要用,就从池中拿,用完还回来。线程池:三大方法、七大参数、四种拒绝策略线程池的好处:降低资源的消耗提高响应的速度方便管理线程复用、可以控制最大并发数、管理线程。三大方法import java.util.concurrent.ExecutorService;import java.util.concurrent.Ex

2020-12-20 17:24:51 97 1

原创 进程通信

进程同步与进程通信很容易混淆,它们的区别在于:进程同步:控制多个进程按一定顺序执行;进程通信:进程间传输信息。进程通信是一种手段,而进程同步是一种目的。也可以说,为了能够达到进程同步的目的,需要让进程进行通信,传输一些进程同步所需要的信息。每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核。在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,I

2020-12-20 16:56:32 117

原创 进程调度算法

先来先服务调度算法(First Come First Served, FCFS)每次从就绪队列中选择最先进入队列的进程,然后一直运行,直到进程退出或阻塞,才会继续从队列中选取下一个进程接着运行。

2020-12-20 13:03:51 255

原创 桶排序

定义桶排序 (Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。思路将要排序的数据分到几个有序的桶中,每个桶里的数据在单独进行排序。桶内排完序之后,再把每个桶里的数据按照顺序依次取出来,组成的序列就是有序的了。对数组[5, 25, 34, 12, 4, 9, 18, 26, 22, 24, 36, 48, 0, 46, 50]进行桶排序:

2020-12-15 17:54:08 108

原创 Java多线程基础

创建线程的三种方式1.继承Thread类public class ThreadTest01 extends Thread { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("run--->" + i); } } public static void main(String[] args)

2020-12-14 18:44:37 83

原创 平衡二叉树—AVL树

在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。特点AVL树本质上还是一颗二叉查找树,具有以下特点:是一颗二叉查找树每个节点的左右子树的高度之差的绝对值(平衡因子)最多为1。下图就是一个AVL树,每个节点旁边标注的是平衡因子:其中节点4的左子树高度为0,右子树不存在,所以平衡因子是0 - (-1) = 1;所有的叶子节点不存在左右子树,所以平衡因子是0。

2020-12-11 20:00:12 161

原创 计数排序

计数排序是一种适合于对数组中最大值与最小值相差不大的数组进行排序。假设对数组 [1, 0, 5, 6, 4, 7, 4, 2, 8, 9, 0, 1, 4, 2, 0, 3, 5, 7, 8, 6] 进行计数排序。我们可以创建一个临时数组a[max+1],临时数组的大小为10,临时数组的下标正好与原数组中的数据对应。我们可以遍历原数组,每遍历一个数,对应临时数组的下标元素就加一。比如无序数组的第一个数是1,那么临时数组下标为1的元素就加一:第二个数是0,那么临时数组下标为0的元素加一:直到未排序

2020-12-10 23:10:31 83

原创 二叉搜索树及二叉树的前中后序遍历(递归和非递归)

定义二叉查找树(Binary Search Tree)又称二叉排序树、二叉搜索树。二叉查找树是为了实现快速查找而生的。不过,它不仅仅支持快速查找一个数据,还支持快速插入、删除一个数据。二叉查找树要求,在树中的任意一个节点都要满足,其左子树中每个节点的值,都要小于这个节点的值,而右子树每个节点的值都大于这个节点的值。这两个都是二叉查找树。查找在二叉查找树中查找一个节点,我们先取根节点,如果它等于我们要查找的数据,那就返回。如果要查找的数据比根节点的值小,那就左子树中递归查找;如果要查找的数据比根节点

2020-12-08 21:50:27 550

原创 二叉堆与堆排序(详细图解)

二叉堆二叉堆是一种特殊的树,有两种特性:堆是一个完全二叉树二叉堆中任意一个父节点的值都大于等于(或小于等于)其左右孩子节点的值。根据第二条特性,可以将二叉堆分为两类:最大堆:父节点的值总是大于或等于左右孩子节点的值。最小堆:父节点的值总是小于或等于左右孩子节点的值。二叉堆的实现1.往堆中插入一个节点由于二叉堆具有完全二叉树的特性,所以我们插入节点时,应该保证它任然是一个完全二叉树。所以,在插入的时候,我们把新节点插入二叉堆的最后一个位置。例如,在下图中插入7。然后在

2020-12-01 23:25:14 1878

原创 注解

注解的格式public @interface MyAnnotation { // 注解的参数:参数类型+参数名 int age();}

2020-11-30 21:04:37 57

原创 反射机制

通过java语言的反射机制可以操作字节码文件,让程序更加灵活。与反射机制相关的重要的类有:1.java.lang.Class:代表整个字节码,代表一个类型,代表整个类2.java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。3.java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法。4.java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量。获取Class的三种方式1

2020-11-30 15:55:55 242

原创 快速排序

快速排序原理从数组中任意选取一个元素,将这个元素称为中轴元素,然后我们将大于中轴元素的元素放在其右边,小于中轴元素的元素放在其左边,然后将中轴元素左边和右边分为两个小的数组,重复此过程,直到数组的大小为1,此时每个元素都处于有序的位置。将第一个元素设置为中轴元素,第二个元素设为i,最后一个元素设为j。然后让i和j从数组的两边向中间扫描。i向右遍历的过程中,如果遇到大于中轴元素的元素则停止移动,j向左遍历的过程中,如果遇到小于中轴元素的元素则停止移动(移动过程中需满足i <= j,不满足则停止移动)

2020-11-29 00:02:25 306

原创 归并排序

1.思路将数组从中间分成前后两个数组,然后继续将前后两个数组从中间划分为更小的数组,直到分成每个数组只有一个元素,此时相当于每个数组都是有序数组,在将两个大小为1的数组合并成一个大小为2的,在把大小为2的数组合并成4的…直到全部小的数组合并起来。所以归并排序的代码其实就是一个分解数组的方法加上一个合并两个有序数组的方法。2.图解3.代码实现public int[] mergeSort(int[] arr, int left, int right) { // 如果left == ri

2020-11-23 23:04:15 78

原创 希尔排序

1.思路希尔排序可以说是插入排序的变种或者说是插入排序的优化,对于插入排序来说,如果一个元素离它的正确位置距离越远,需要移动的次数就越多,这样速度就比较慢。而希尔排序的思想就是先让数组进行分组,再进行插入排序。对一个数组大小为h的数组,刚开始分成h/2个数组进行插入排序,每个数组的元素间距为h/2,接着分成h/4个数组进行插入排序,元素间距为h/4,直到分组后的数组只有一个,就是最后一次插入排序。这种分组插入排序的方式可以优化元素离正确位置较远而消耗时间过长的情况。2.图解对数组[8, 9, 1, 7

2020-11-21 22:25:43 102

原创 插入排序

1.思路:我们可以先思考一个问题,怎样往一个有序数组中添加一个元素并且保证这个有序数组依然有序。解决这个问题很简单,只需要遍历数组找到应该插入的位置即可。插入排序就是这种思想。我们可以将数组分为已排序区间和未排序区间,初始时已排序区间只有一个元素,可以视为一个有序数组。每次拿出未排序区间的第一个元素插入已排序区间,重复这个过程直到未排序区间为空,插入排序结束。2.图解:对数组[4,5,6,1,3,2]进行插入排序,步骤如下图:3.代码实现:public void insertSort (int[]

2020-11-20 22:32:15 148 2

空空如也

空空如也

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

TA关注的人

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