Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解
Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解
- 1.Java虚拟机运行时数据区图
- 2. 堆的默认分配图
- 3.方法区结构图
- 4.对象的内存布局图
- 5.对象头的Mark Word图
- 6.对象与Monitor关联结构图
- 7.Java Monitor的工作机理图:
- 8.创建一个对象内存分配流程图
- 9.可达性分析算法判定对象存活
- 10.标记-清除算法示意图
- 11.标记-复制算法示意图
- 12.标记-整理算法示意图
- 13.垃圾收集器组合图
- 14.类的生命周期图
- 15.类加载器双亲委派模型图
- 16.栈帧概念结构图
- 17.Java内存模型图
- 18.线程状态转换关系图
- 19. Class文件格式图
- 20.JVM参数思维导图
- Spring的生命周期
- TCP三次握手,四次挥手
- 线程池执行流程图
- JVM内存结构
- Java内存模型
- SpringMVC执行流程图
- JDBC执行流程
- Spring cloud组件架构
- dubbo 调用
1.Java虚拟机运行时数据区图
JVM内存结构是Java程序员必须掌握的基础。
程序计数器
- 程序计数器,可以看作当前线程所执行的字节码的行号指示器
- 它是线程私有的。
Java虚拟机栈
- 线程私有的,生命周期与线程相同。
- 每个方法被执行的时候都会创建一个"栈帧",用于存储局部变量表(包括参数)、操作数栈、动态链接、方法出口等信息。
- 局部变量表存放各种基本数据类型boolean、byte、char、short等
本地方法栈
- 与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务。
Java堆
- Java堆是java虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在JVM启动时创建。
- 其大小通过-Xms和-Xmx参数设置,-Xms为JVM启动时申请的最小内存,-Xmx为JVM可申请的最大内存。
方法区
- 它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。
- -可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小。
2. 堆的默认分配图
- Java堆 = 老年代 + 新生代
- 新生代 = Eden + S0 + S1
- 新生代与老年代默认比例的值为 1:2 ,可以通过参数 –XX:NewRatio 配置。
- 默认的,Eden : from : to = 8 : 1 : 1 ,可以通过参数–XX:SurvivorRatio 来设定
3.方法区结构图
方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
4.对象的内存布局图
一个Java对象在堆内存中包括对象头、实例数据和补齐填充3个部分:
- 对象头包括Mark Word(存储哈希码,GC分代年龄等) 和 类型指针(对象指向它的类型元数据的指针),如果是数组对象,还有一个保存数组长度的空间
- 实例数据是对象真正存储的有效信息,包括了对象的所有成员变量,其大小由各个成员变量的大小共同决定。
- 对齐填充不是必然存在的,仅仅起占位符的作用。
5.对象头的Mark Word图
- Mark Word 用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等。
- 在32位的HotSpot虚拟机中,如果对象处于未被锁定的状态下,那么Mark Word的32bit空间里的25位用于存储对象哈希码,4bit用于存储对象分代年龄,2bit用于存储锁标志位,1bit固定为0,表示非偏向锁。
6.对象与Monitor关联结构图
对象是如何跟monitor有关联的呢?
一个Java对象在堆内存中包括对象头,对象头有Mark word,Mark word存储着锁状态,锁指针指向monitor地址。这其实是Synchronized的底层
7.Java Monitor的工作机理图:
Java 线程同步底层就是监视锁Monitor~,如下是Java Monitor的工作机理图:
- 想要获取monitor的线程,首先会进入_EntryList队列。
- 当某个线程获取到对象的monitor后,进入_Owner区域,设置为当前线程,同时计数器_count加1。
- 如果线程调用了wait()方法,则会进入_WaitSet队列。它会释放monitor锁,即将_owner赋值为null,_count自减1,进入_WaitSet队列阻塞等待。
- 如果其他线程调用 notify() / notifyAll() ,会唤醒_WaitSet中的某个线程,该线程再次尝试获取monitor锁,成功即进入_Owner区域。
- 同步方法执行完毕了,线程退出临界区,会将monitor的owner设为null,并释放监视锁。
8.创建一个对象内存分配流程图
- 对象一般是在Eden区生成。
- 如果Eden区填满,就会触发Young GC。
- 触发Young GC的时候,Eden区实现清除,没有被引用的对象直接被清除。
- 依然存活的对象,会被送到Survivor区,Survivor =S0+S1.
- 每次Young GC时,存活的对象复制到未使用的那块Survivor 区,当前正在使用的另外一块Survivor 区完全清除,接着交换两块Survivor 区的使用状态。
- 如果Young GC要移送的对象大于Survivor区上限,对象直接进入老年代。
- 一个对象不可能一直呆在新生代,如果它经过多次GC,依然活着,次数超过-XX:MaxTenuringThreshold的阀值,它直接进入老年代。简言之就是,对象经历多次滚滚长江,红尘世事,终于成为长者(进入老年代)
9.可达性分析算法判定对象存活
可达性分析算法是用来判断一个对象是否存活的~
算法的核心思想:
通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始根据引用关系向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可能再被使用。
10.标记-清除算法示意图
- 标记-清除算法是最基础的垃圾收集算法。
- 算法分为两个阶段,标记和清除。
- 首先标记出需要回收的对象,标记完成后,统一回收掉被标记的对象。
- 当然可以反过来,先标记存活的对象,统一回收未被标记的对象。
- 标记-清除 两个缺点是,执行效率不稳定和内存空间的碎片化问题~
11.标记-复制算法示意图
- 1969年 Fenichel提出“半区复制”,将内存容量划分对等两块,每次只使用一块。当这一块内存用完,将还存活的对象复制到另外一块,然后把已使用过的内存空间一次清理掉~
- 1989年,Andrew Appel提出“Appel式回收”,把新生代划分为较大的Eden和两块较小的Survivor空间。每次分配内存只使用Eden和其中一块Survivor空间。发生垃圾收集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上。Eden和Survivor比例是8:1~
- “半区复制”缺点是浪费可用空间,并且,如果对象存活率高的话,复制次数就会变多,效率也会降低。
12.标记-整理算法示意图
- 1974年,Edward 提出“标记-整理”算法,标记过程跟“标记-清除”算法一样,接着让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存~
- 标记-清除算法和标记整理算法本质差异是:前者是一种非移动式的回收算法,后者是移动式的回收算法。
- 是否移动存活对象都存在优缺点,移动虽然内存回收复杂,但是从程序吞吐量来看,更划算;不移动时内存分配更复杂,但是垃圾收集的停顿时间会更短,所以看收集器取舍问题~
- Parallel Scavenge收集器是基于标记-整理算法的,因为关注吞吐。CMS收集器是基于标记-清除算法的,因为它关注的是延迟。
13.垃圾收集器组合图
- 新生代收集器:Serial、ParNew、Parallel Scavenge
- 老年代收集器:CMS、Serial Old、Parallel Old
- 混合收集器:G1
14.类的生命周期图
一个类从被加载到虚拟机内存开始,到卸载出内存为止,这个生命周期经历了七个阶段:加载、验证、准备、解析、初始化、使用、卸载。
加载阶段:
- 通过一个类的全限定名来获取定义此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
验证:
- 验证的目的是确保Class文件的字节流中包含的信息满足约束要求,保证这些代码运行时不会危害虚拟机自身安全
- 验证阶段有:文件格式校验、元数据校验、字节码校验、符号引用校验。
准备
- 准备阶段是正式为类中定义的变量(静态变量)分配内存并设置类变量初始值的阶段。
解析
- 解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
初始化
- 到了初始化阶段,才真正开始执行类中定义的Java字节码。
15.类加载器双亲委派模型图
双亲委派模型构成
启动类加载器,扩展类加载器,应用程序类加载器,自定义类加载器
双亲委派模型工作过程是
如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。
为什么需要双亲委派模型?
如果没有双亲委派,那么用户是不是可以自己定义一个java.lang.Object的同名类,java.lang.String的同名类,并把它放到ClassPath中,那么类之间的比较结果及类的唯一性将无法保证,因此,双亲委派模型可以防止内存中出现多份同样的字节码。
16.栈帧概念结构图
栈帧是用于支持虚拟机进行方法调用和方法执行背后的数据结构。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址信息。
局部变量表
- 是一组变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。
- 局部变量表的容量以变量槽(Variable Slot)为最小单位。
操作数栈
- 操作数栈,也称操作栈,是一个后入先出栈。
- 当一个方法刚刚开始执行的时候, 该方法的操作数栈也是空的, 在方法的执行过程中, 会有各种字节码指令往操作数栈中写入和提取内容, 也就是出栈与入栈操作。
动态连接
- 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用, 持有引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。
方法返回地址
- 当一个方法开始执行时, 只有两种方式退出这个方法 。一种是执行引擎遇到任意一个方法返回的字节码指令。另外一种退出方式是在方法执行过程中遇到了异常。
17.Java内存模型图
- Java内存模型规定了所有的变量都存储在主内存中
- 每条线程还有自己的工作内存
- 线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝
- 线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。
- 不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。
18.线程状态转换关系图
Java语言定义了6种线程池状态:
- 新建(New):创建后尚未启动的线程处于这种状态
- 运行(Running):线程开启start()方法,会进入该状态。
- 无限等待(Waiting):处于这种状态的线程不会被分配处理器执行时间,一般LockSupport::park(),没有设置了Timeoout的Object::wait()方法,会让线程陷入无限等待状态。
- 限期等待(Timed Waiting):处于这种状态的线程不会被分配处理器执行时间,在一定时间之后他们会由系统自动唤醒。sleep()方法会进入该状态~
- 阻塞(Blocked):在程序等待进入同步区域的时候,线程将进入这种状态~
- 结束(Terminated):已终止线程的线程状态,线程已经结束执行
19. Class文件格式图
- u1、u2、u4、u8 分别代表1个字节、2个字节、4个字节和8个字节的无符号数
- 表是由多个无符号数或者其他表作为数据项构成的复合数据类型
- 每个Class文件的头四个字节被称为魔数(记得以前校招面试,面试官问过我什么叫魔数。。。)
- minor和major version表示次版本号,主版本号
- 紧接着主次版本号之后,是常量池入口,常量池可以比喻为Class文件里的资源仓库~
20.JVM参数思维导图
Spring的生命周期
- 首先容器启动后,对bean进行初始化
- 按照bean的定义,注入属性
- 检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给bean,如BeanNameAware等
- 以上步骤,bean对象已正确构造,通过实现BeanPostProcessor接口,可以再进行一些自定义方法处理。如:postProcessBeforeInitialzation。
- BeanPostProcessor的前置处理完成后,可以实现postConstruct,afterPropertiesSet,init-method等方法,
- 增加我们自定义的逻辑,
- 通过实现BeanPostProcessor接口,进行postProcessAfterInitialzation后置处理
- 接着Bean准备好被使用啦。
- 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法
- 通过给destroy-method指定函数,就可以在bean销毁前执行指定的逻辑
TCP三次握手,四次挥手
tcp的三次握手四次挥手是每个程序员都应该熟悉的。
三次握手:
- 第一次握手(SYN=1, seq=x),发送完毕后,客户端进入 SYN_SEND 状态
- 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服务器端进入 SYN_RCVD 状态。
- 第三次握手(ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手,即可以开始数据传输。
四次挥手:
- 第一次挥手(FIN=1,seq=a),发送完毕后,客户端进入 FIN_WAIT_1 状态
- 第二次挥手(ACK=1,ACKnum=a+1),发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态
- 第三次挥手(FIN=1,seq=b),发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。
- 第四次挥手(ACK=1,ACKnum=b+1),客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。
线程池执行流程图
线程池:一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,这避免了在处理短时间任务时创建与销毁线程的代价。
执行流程
- 提交一个任务,线程池里存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程去处理提交的任务。
- 如果线程池核心线程数已满,即线程数已经等于corePoolSize,一个新提交的任务,会被放进任务队列workQueue排队等待执行。
- 当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列workQueue也满,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没到达,创建一个非核心线程执行提交的任务。
- 如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。
JDK提供了四种拒绝策略处理类
- AbortPolicy(抛出一个异常,默认的)
- DiscardPolicy(直接丢弃任务)
- DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)
- CallerRunsPolicy(交给线程池调用所在的线程进行处理)
JVM内存结构
程序计数器(PC 寄存器)
程序计数器是一块较小的内存空间,可以看作当前线程所执行的字节码的行号指示器。在虚拟机的模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成。
Java虚拟机栈
- 与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期与线程相同
- 每个方法被执行的时候都会创建一个"栈帧",用于存储局部变量表(包括参数)、操作数栈、动态链接、方法出口等信息。每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
- 局部变量表存放各种基本数据类型boolean、byte、char、short等
本地方法栈
与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务。
Java堆
- GC堆是java虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在JVM启动时创建。
- 其大小通过-Xms(最小值)和-Xmx(最大值)参数设置,-Xms为JVM启动时申请的最小内存,-Xmx为JVM可申请的最大内存。
- 由于现在收集器都是采用分代收集算法,堆被划分为新生代和老年代。新生代由S0和S1构成,可通过-Xmn参数来指定新生代的大小。
- 所有对象实例以及数组都在堆上分配。
- Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分内容将在类加载后放到方法区的运行时常量池中。
方法区
- 也称”永久代” ,它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小。
- 运行时常量池:是方法区的一部分,其中的主要内容来自于JVM对Class的加载。
- Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分内容将在类加载后放到方法区的运行时常量池中。
Java内存模型
- Java的多线程之间是通过共享内存进行通信的,在通信过程中会存在一系列如可见性、原子性、顺序性等问题,而JMM就是围绕着多线程通信以及与其相关的一系列特性而建立的模型。JMM定义了一些语法集,这些语法集映射到Java语言中就是volatile、synchronized等关键字。
- Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。
SpringMVC执行流程图
- User向服务器发送request,前端控制Servelt DispatcherServlet捕获;
- DispatcherServlet对请求URL进行解析,调用HandlerMapping获得该Handler配置的所有相关的对象,最后以HandlerExecutionChain对象的形式返回.
- DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter.
- 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)
- Handler执行完成后,返回一个ModelAndView对象到DispatcherServlet
- 根据返回的ModelAndView,选择一个适合的ViewResolver
- ViewResolver 结合Model和View,来渲染视图
- 将渲染结果返回给客户端。
JDBC执行流程
JDBC执行流程:
- 连接数据源
- 为数据库传递查询和更新指令
- 处理数据库响应并返回的结果
Spring cloud组件架构
Spring Cloud是一个基于Spring Boot实现的云原生应用开发工具,它为基于JVM的云原生应用开发中涉及的配置管理、服务发现、熔断器、智能路由、微代理、控制总线、分布式会话和集群状态管理等操作提供了一种简单的开发方式。
- Eureka 负责服务的注册与发现。
- Hystrix 负责监控服务之间的调用情况,起到熔断,降级作用。
- Spring Cloud Config 提供了统一的配置中心服务。
- 所有对外的请求和服务,我们都通过Zuul来进行转发,起到 API 网关的作用
- 最后我们使用 Sleuth+Zipkin 将所有的请求数据记录下来,方便我们进行后续分析。
- Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
- 它是一个基于HTTP和TCP的客户端负载均衡器。
- Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。
dubbo 调用
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的远程服务调用方案,这容易和负载均衡弄混,负载均衡是对外提供一个公共地址,请求过来时通过轮询、随机等,路由到不同server。
- Provider: 暴露服务的服务提供方。
- Consumer: 调用远程服务的服务消费方。
- Registry: 服务注册与发现的注册中心。
- Monitor: 统计服务的调用次调和调用时间的监控中心。
- Container: 服务运行容器。
Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解的更多相关文章
- Java基础篇(JVM)——类加载机制
这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
- Java基础技术JVM面试【笔记】
Java基础技术JVM面试[笔记] JVM JVM 对 java 类的使用总体上可以分为两部分:一是把静态的 class 文件加载到 JVM 内存,二是在 JVM 内存中进行 Java 类的生命周期管 ...
- Java基础-考察JVM内部结构的常用工具介绍
Java基础-考察JVM内部结构的常用工具介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们可以通过jvisualvm.exe考察jvm内部结构.而jvisualvm.exe ...
- Java基础篇(JVM)——字节码详解
这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...
- Java基础:JVM垃圾回收算法
众所周知,Java的垃圾回收是不需要程序员去手动操控的,而是由JVM去完成.本文介绍JVM进行垃圾回收的各种算法. 1. 如何确定某个对象是垃圾 1.1. 引用计数法 1.2. 可达性分析 2. 典型 ...
- Java 基础 多线程和线程池基础
一,多线程 1.1 多线程介绍 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负 ...
- JAVA基础拾遗-论线程池的线程粒度划分与深浅放置
摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...
- 简明易懂,将细节隐藏,面向新手树立web开发概念——学完Java基础语法,超快速上手springboot+mybatiJavaWeb开发
简明易懂,将细节隐藏,面向新手树立web开发概念 --学完Java基础语法,超快速上手JavaWeb开发 Web本质(先忽视各种协议) Web应用可以理解为浏览器和服务器之间的交互. 我们可以看一个简 ...
- Java基础篇——JVM之GC原理(干货满满)
原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10697554.html ,多多支持哈! 一.什么是GC? GC是垃圾收集的意思,内存处理是 ...
随机推荐
- 仿小米logo案例
效果:做一个具有logo能过渡切换效果,类似于小米网站的logo 思路:将两个用于切换的logo以文字形式嵌入活动块banner的左右半,活动块banner的上级是主展示块box,初态只展示右半log ...
- 远程分支删除后,git branch -a还能看到的解决方法
详情https://www.cnblogs.com/wangiqngpei557/p/6058115.html 大家在删除远程分支后 git branch -a 还是可以看到已删除的远程分支,时间一长 ...
- 阿里云centos7安装mysql8数据库
一.安装mysql 1. mysql官网查找仓库源镜像,选择downloads https://www.mysql.com/downloads/ 2. 找到社区版 3. 选择yum仓库 4. 选择对应 ...
- 2018年第九届蓝桥杯B组(201806-----递增三元组)
给定三个整数数组 A = [A1, A2, - AN], B = [B1, B2, - BN], C = [C1, C2, - CN], 请你统计有多少个三元组(i, j, k) 满足: 1 < ...
- mysql 连接url中需要添加useUnicode=true&characterEncoding=UTF-8
下面是示例: 数据库中Username是张三 在数据库配置时没有配置编码 useUnicode=true&characterEncoding=UTF-8 导致期望与实际不同 配置useUni ...
- SonarQube学习(五)- SonarQube之自定义规则使用
一.前言 古人云:"欲速则不达",最近真的是深有体会.学习也是如此,不是一件着急的事,越是着急越不会. 就拿SonarQube来说吧,去年年末就想学来着,但是想着想着就搁置了,有时 ...
- 【JDBC核心】操作 BLOB 类型字段
操作 BLOB 类型字段 MySQL BLOB 类型 MySQL 中,BLOB 是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据. 插入 BLOB 类型的数据必须使用 Pre ...
- 【C++】《Effective C++》第三章
第三章 资源管理 条款13:以对象管理资源 当申请一块动态内存时,可能会发生内存泄漏. class Investment {}; void f() { Investment* pInv = creat ...
- 浅谈sql索引
索引是什么 假如你手上有一个你公司的客户表,老板说找什么客户你就得帮他找出来. 客户不多的时候,你拿着手指一行一行滑,费不了多少时间就能找到. 后来公司做大了,客户越来越多,好几页的客户,你发现,一行 ...
- 基于 OpenMP 的奇偶排序算法的实现
代码: #include <omp.h> #include <iostream> #include <cstdlib> #include <ctime> ...