- 博客(130)
- 问答 (1)
- 收藏
- 关注
原创 Java8新特性-Optional类
一、Optional简介与使用1.1 Optional简介在Java应用开发的过程中,NPE(NullPointerException)问题是一个非常常见的问题,为了避免空指针异常对代码的破坏,我们不得不在各种可能出现空指针的地方通过if-else来校验,造成代码累赘,严重影响代码可读性。为了优雅的解决NPE问题,Google公司著名的Guava项目引入了Optional类,Guava通过检查空值的方式来防止代码污染,它鼓励程序员编写简单干净的代码。受到Google Guava项目的启发,Optiona
2021-09-22 17:20:26 662
原创 详解操作系统线程
一、线程概述1.1 为什么需要线程一个应用通常需要同时处理很多独立的工作,同时执行的任务称为”执行流“,由于各个执行流是独立的,所以在多核CPU中,不希望他们是顺序执行的。在《详解操作系统进程》的最后面,我们提高了创建子进程可以得到两个并发执行的流,能够并发完成不同的操作,早期,每个执行流都要创建一个进程来实现,但创建子进程的弊端是:父子进程拥有完全相同的内存镜像、变量、寄存器以及除了进程标识符以外所有的东西,非常浪费内存空间,于是就产生了轻量级进程——线程。由于线程比进程更轻量级,所以
2021-07-16 14:09:33 1801
原创 详解HTTP协议
一、HTTP简介传输层使用TCP客户端发起一个与服务器的TCP连接(建立套接字),端口号为80服务器接收客户端的TCP连接在浏览器与Web服务器交换HTTP报文(应用层协议报文)TCP连接关闭HTTP是无状态的服务器并不维护关于客户的任何信息维护状态的协议很复杂!必须维护历史信息(状态)如果服务器/客户端死机,它们的状态信息可能不一致,但二者的信息必须一致无状态的服务器能够支持更多的客户端Web服务器启动后,创建一个守护Socket,监听80号端口,当有客户端浏览器发起请求
2021-07-09 16:35:37 872 1
原创 详解WebSocket协议
一、WebSocket协议WebSocket可以实现客户端与服务器间双向、基于消息的文本或二进制数据传输。它是浏览器中最靠近套接字的API,但WebSocket连接远远不是一个网络套接字,因为浏览器在这个简单的API之后隐藏了所有的复杂性,而且还提供了更多服务:连接协商和同源策略与既有HTTP基础设施的互操作基于消息的通信和高效消息分帧子协议协商及可扩展能力WebSocket是浏览器中最通用最灵活的一个传输机制,其极简的API可以让我们在客户端和服务器之间以数据流的形式实现各种应用数据交换(
2021-07-09 16:34:25 4253
原创 Web页面请求全流程
Web页面请求的全过程场景:小李刚入职行政人员为他分配了工作电脑,小李用一根网线将电脑连接至工位的交换机上,交换机又与公司的路由器相连,如下图所示。公司的路由器与ISP网络连通,CMNET为中国移动的ISP网络,CMNET为公司提供了DNS服务,DNS服务器驻留在CMNET网络中。假设:DHCP服务器运行在公司路由器上请求过程:IP分配电脑启动后,操作系统封装DHCP应用报文,传输层使用UDP协议的68号客户端端口进行发送,目的地为DHCP服务器的67号端口,传输层将源端口和目标端口放
2021-07-09 16:32:08 1987 2
原创 Redis持久化策略
Redis作为一款内存数据库,因为是内存读写,所以性能很强,但内存存储是易失性的,断电或系统奔溃都会导致数据丢失,因此Redis也需要将其数据持久化到磁盘上面,当Redis服务重启时,会把磁盘上的数据再加载进内存。Redis提供了两种持久化机制:RDB快照(snapshot)和AOF(append-only file)日志。一、RDB快照1.1 RDB原理Redis是单线程操作的,这个线程需要同时负责多个客户端套接字的并发读写操作和内存数据的读写操作。而在RDB的持久化方式下,Redis还需要进行
2022-05-27 21:16:23 3489 1
原创 Redis基本数据类型与常用命令
一、Redis常用数据结构Redis作为Key-Value类型的数据库,所有的key都是字符串类型,而通常所说的Redis的数据结构指的是value的数据结构,Redis基本的数据结构有:string、hash、list、set、zset,还有一些高级的数据结构比如bitmap,但这些高级的数据结构都是基本数据结构的变种,后面会有文章特意介绍这些基本数据结构和高级数据结构底层实现的区别。1.1 String这是Redis中最常用的数据结构,下面是一些基本命令:// 给键key设置一个字符串值valu
2022-05-26 18:39:59 693
原创 Redis安装配置
Redis作为内存数据库的代表作,具有超高的性能,理论上单节点吞吐量可以达到10w,作为重要的产生组件,也是应用最广泛的。1.1 安装Redis文章就从安装开始认识Redis,下载地址:http://redis.io/download在linux服务器上下载安装Redis:// 在Redis官网将鼠标放在下载的url上右键复制链接地址即可[root@lizhi redis]# wget https://download.redis.io/releases/redis-5.0.14.tar.gz/
2022-05-26 18:29:11 467
原创 新一代虚拟机GraalVM
在JDK10以前,能进行性能优化的即时编译器只有C2,但C2编译器的代码据说已经变得非常庞大且臃肿,同时伴随着云原生时代的到来,Java这种需要借助JDK才能运行的语言就显得格外臃肿,于是就有了Graal编译器的诞生,Graal编译器提供了非常强悍的能力,所以通常把Graal编译器与HotSpot合称为新一代的虚拟机——GraalVM。GraalVM是一个高性能JDK发行版,旨在加速用Java和其他语言编写的应用程序的执行,并支持JavaScript、Ruby、Python和许多其他流行语言。从上面的
2022-05-25 18:32:57 1524 2
原创 详解JVM的即时编译
JVM之所以拥有强大的生态,是因为它是跨语言性的,JVM只识别字节码文件,不论是什么语言编写的代码,只要经过编译后能生成.class的字节码文件,JVM都可以进行解析。当然这些字节码文件都要符合JVM对于Class文件的格式定义,不能随便一个文件将后缀改成.classs就能行的。像Groovy、Kotlin、Scala等语言,它们编译后生成的都是字节码文件,所以它们可以在JVM上运行。字节码文件的内容除了一些常量池的一些信息外,其他基本都是每个方法中语句对应的字节码指令,像下面这样包含了部分main(
2022-05-24 18:58:56 989
原创 详解JVM的常量池
在《JVM类加载机制》和《JVM内存模型》这两篇文章都对常量池和运行时常量池做了不少介绍,这篇文章再次聚焦常量池,搞清楚常量池到底都有什么。一、静态常量池与运行时常量池静态常量池也可以称为Class常量池,也就是每个.java文件经过编译后生成的.class文件,每个.class文件里面都包含了一个常量池,因为这个常量池是在Class文件里面定义的,也就是.java文件编译后就不会在变了,也不能修改,所以称之为静态常量池。以下面的Test.java文件为例:public class Test {
2022-05-24 13:36:29 6264 6
原创 JVM调优工具(二)
上一篇文章介绍了JDK自带的一些可以查看JVM各种参数的工具,但在linux服务器上没有可视化的工具使用,如果通过远程连接到linux服务器还需要启动jstatd和JMX等,是存在一些安全隐患的。但JDK自带的一些基本命令行工具虽然可以查看内容,但也不是特别方便,不能够直观的看到JVM内部的情况,于是阿里巴巴在2018年9月推出了一款Java诊断工具Arthas,它支持JDK6+,采用命令行的交互方式,可以很方便的定位和诊断线上程序运行的问题。Arthas可以看作是对JDK工具包的一种再次封装,同时提供
2022-05-23 16:49:32 529
原创 JVM调优工具(一)
前面的文章已经介绍了JVM对象创建时的内存分配、类加载机制以及垃圾收集等核心的内容,对JVM的内存模型基本有了比较完整的了解。但这些都只是理论,当程序运行遇到问题时,更多的时候是需要根据现象然后结合理论才能做出合理的判断。而JDK就提供了很多的工具来帮助开发人员获取程序运行时的各种数据,包括异常堆栈、JVM运行日志、GC日志、线程快照文件、堆转储快照文件等等。这篇文章就借助部分常用工具,结合具体的应用程序来查看程序运行过程中的各种数据,对这些数据进行分析,继而更好的调整JVM参数。一、基础工具1.1
2022-05-21 19:16:43 1674
原创 详解ZGC垃圾收集器
从G1垃圾收集器开始,后面的垃圾收集器都不再将堆按照新生代和老年代作为整体进行回收,都采用了局部收集的设计思想。可能是由于G1作为第一代局部收集的垃圾收集器,所以它继续保留了新生代和老年代的概念,笔者认为从局部收集和分区的内存布局来看,按代收集理论已经没有什么特别存在的必要了。一、ZGC的设计思路1.1 ZGC的内存布局新一代的垃圾收集器ZGC(Z Garbage Collector)就完全抛弃了按代收集理论,它与G1一样将内存划分成各个小的区域的,但与G1有所不同的是,ZGC的各个内存区域称为页面
2022-05-20 18:53:00 4810 1
原创 详解G1垃圾收集器
G1(Garbage-First)作为继CMS之后新一代面向服务器的垃圾收集器,它已经不再严格按照之前老年代和新生代的划分来进行垃圾收集,即它是一个老年代和新生代共用的垃圾收集器。G1更多是在多处理器(或多核)以及大内存的机器上发挥优势,在满足指定GC停顿时间要求的同时,还具备高吞吐量的能力。这篇文章主要从G1的设计理念和垃圾回收过程来详细介绍。一、设计思想在《GC收集算法与GC收集器》这篇文章中介绍了JVM中经典的垃圾收集器,这些垃圾收集器的共性是在整个垃圾收集过程中,一定会发生Stop The
2022-05-19 17:15:37 11405 3
原创 GC算法与GC收集器
Java相比于C++这样语言,除了跨平台的特性外,最突出的特点就是垃圾回收机制。C++的开发人员还需要手动分配和回收内存,但JVM直接承担起了垃圾回收的重任,开发人员可以专注于业务开发,不需要再去关心复杂的内存回收。JVM的垃圾收集包含了两部分内容:垃圾收集算法与垃圾收集器,这两者是理论与实践的关系。前者提供理论依据,后者是对理论的实现。在《JVM内存分配机制》这篇文章中介绍过了堆空间是按照新生代和老年代来划分的,这是因为根据对象的不同生命周期划分不同的区域后,垃圾回收时可以根据各个区域的特性,采用不同
2022-05-18 19:45:39 1461 1
原创 JVM内存分配机制
Java虚拟机最重要的工作就是如何给对象分配内存空间,以及通过GC如何回收已经不再使用的内存空间。这篇文章主要介绍JVM中的Java对象是创建过程、对象内存的分配机制以及对象内存的回收机制。一、对象的创建在前面的文章《JVM类加载机制》中讲过,JVM中所有对象的创建,都需要先将对应的.class文件加载进内存,所以JVM中通常一个对象的创建包含了如下几个步骤:1.1 检查类是否加载当JVM执行到new字节码指令时,首先会去运行时常量池检查该指令指定的参数能够找到对应类的符号引用,并检查这个符号引用
2022-05-17 13:54:34 3405 1
原创 JVM内存模型
Java在诞生之初就提出了"Write once,Run Anywhere"的口号,而这些都得益于JVM(Java Vritual Machine),可以提前在不同的运行环境(linux或windows等)上安装JDK之后,就可以让同一份代码在任何地方运行了。而这里的JDK(Java Development Kit)是Java语言、Java虚拟机和Java类库的统称。一、JDK体系结构与Java跨平台特性1.1 JDK体系结构JDK是一个非常庞大的体系,里面包含了JVM、Java SE API(核心类
2022-05-14 21:16:34 18460 2
原创 JVM类加载机制
在Java中,通常会说万物皆是对象,即便是一个编译后的.class文件,它也需要变成一个对象,才能在Java中使用,而将.class文件变成对象的过程就是类加载机制。这篇文章主要介绍Java的类加载机制的原理,包括常用的类加载器和设计原理。一、类加载过程以下面的简单程序为例:public class ClassLoadTest { public static void main(String[] args) { System.out.println("Hello Word")
2022-05-14 11:34:15 1426
原创 详解InnoDB的Buffer Pool
在上一篇文章《InnoDB存储结构》中,可以从InnoDB的体系结构中看到InnoDB存储引擎主要包含两部分内容,其中表空间结构这些在该文章已经介绍了,而这篇文章将会重点介绍Buffer Pool。一、简介InnoDB存储引擎在处理客户端的请求时,当需要访问某个页的数据时,就会把完整的页的数据全部加载到内存中,也就是说即使我们只需要访问一个页的一条记录,那也需要先把整个页的数据加载到内存中。将整个页加载到内存中后就可以进行读写访问了,在进行完读写访问之后并不着急把该页对应的内存空间释放掉,而是将其缓存起
2022-05-03 14:26:43 2431
原创 InnoDB存储结构
InnoDB存储引擎是为数据页为操作的基本单位,默认大小为16KB,而这些数据页是存储在磁盘中,当需要查询数据时,InnoDB怎么知道每条记录放在磁盘的哪个位置,这里面就涉及到了InnoDB记录的存储存储结构、索引页结构以及表空间等,这篇文章主要就是介绍记录是怎么存储在磁盘中,除了记录业务数据外,还需要记录哪些内容。一、InnoDB记录存储结构我们平时在使用数据库时,是以记录为单位读取或修改数据,这些记录在磁盘上的存放方式称为行格式或记录格式。InnoDB存储引擎设计了四种不同类型的行格式,分别是:Co
2022-05-02 19:10:16 2597
原创 优化器内部优化规则
在前面介绍Explain使用的文章《Explain使用详解》中,简单的提到了show warnings的使用,通过该语句可以查看一条SQL经过优化器处理后,真正要执行的SQL是什么样子。这篇文章就介绍一些MySQL优化器内部优化的规则,对于开发人员来说,了解MySQL内部的优化规则可以让优化工作在书写SQL时就完成,不需要优化器再帮忙优化,这样也可以提升SQL执行的效率。对于一个SQL的执行,MySQL在执行的过程中会有很多的优化措施,比如索引下推、回表中的MRR、索引合并等等。这里主要介绍三大类优化
2022-05-02 12:14:36 1006
原创 MySQL索引合并
MySQL在一般情况下执行一个查询时最多只会用到单个二级索引,但存在有特殊情况,也可能在一个查询中使用到多个二级索引,MySQL中这种使用到多个索引来完成一次查询的执行方法称之为:索引合并/index merge在上一篇文章《MySQL内核查询成本计算》中提到,会先分析单独使用这些索引的成本,最后还要分析是否可能使用到索引合并。而使用索引合并的前提条件是要满足既定的一些规范,其中就包括下面三种:一、Intersection合并Intersection是交集的意思。某个查询可以使用多个二级索引,将从多
2022-05-02 10:44:45 2468
原创 MySQL内核查询成本计算
在《索引优化(一)》的文章中,提到可以通过trace工具来查看MySQL是如何选择索引的。使用方式:set session optimizer_trace="enabled=on",end_markers_in_json=on;select * from employees where name > 'lizhi' order by position;SELECT * FROM information_schema.OPTIMIZER_TRACE;在选择索引的过程中,最重要的指标就是查询成
2022-05-01 23:12:20 1086
原创 表结构及索引设计
良好的表结构设计是高性能的基础,要根据系统将要执行的业务来设计,需要权衡多种因素。但在数据库设计上,有个非常重要的设计准则,称为范式设计。这篇文章将介绍数据库表设计中的范式和反范式设计以及索引的深度辨析和索引创建的策略。一、范式设计在关系型数据库中,想要设计好表之间的关系,就需要使关系满足一定的约束条件,而这些约束条件就是数据库设计中的范式,数据库设计的范式分为多个等级,每一个等级都是在上一个等级上的延申。目前关系型数据库分为六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯
2022-05-01 21:25:04 997
原创 MVCC机制与Buffer Pool
在上一篇文章《事务隔离级别与锁机制》中介绍了,读已提交和可重复度隔离级别都用到了MVCC机制,MySQL在可重复读的事务隔离级别下,可以解决数据的不可重复读问题,就算其他事务对访问的数据进行了修改,也不影响当前事务两次读取的结果。而这个隔离性就是由**MVCC(Multi-Version Concurrency Control)**机制来保证的,对一行数据的读写操作不要进行加锁就可以保证隔离性,达到了一致性非锁定读的效果。注:MySQL在读已提交和可重复读两种事务隔离级别下都实现了MVCC机制这篇文章就
2022-05-01 18:42:26 760
原创 浅谈事务隔离级别与锁机制
数据库中通常会存在并发执行多个事务的情况,而这些并发的事务如果操作的有相同的数据,就会导致脏写、脏读等问题。MySQL为了解决数据库并发事务导致的脏写、脏读、不可重复读、幻读等问题,设计了事务隔离等级、锁机制和MVCC(多版本并发控制)机制,通过一整套的机制来解决多事务并发问题。一、数据库事务1.1 事务特性事务是由一组SQL语句组成的逻辑处理单元,事务具有以下四大特性,称为事务的ACID特性:原子性:事务是一个原子操作单元,其内部的SQL语句要么全部执行成功,要么都不执行一致性:在事务开始和完
2022-05-01 17:00:47 1603 1
原创 索引优化(二)
在上一篇《索引优化(一)》的文章中,已经介绍了联合索引、索引下推、排序分组和文件排序的优化策略,还介绍了如果通过trace工具来查看MySQL选择执行方案的过程,这边文章继续介绍常用的索引优化以及如何设计索引。一、分页查询优化很多时候,业务系统需要实现分页展示的功能,可能会用到下面的SQL:select * from employees limit 10000,10;该SQL从表中取出从10001开始的10条数据。虽然从结果看是只查询了10条数据,但实际上这条SQL是先读取10010条记录,然后抛
2022-04-30 10:29:56 590
原创 索引优化(一)
对于任何一个后端的开发人员来说,索引优化是必备的技能,接下来会通过两篇文章来介绍如何优化索引以及如何设计好的索引。一、数据准备创建一个员工表,除了主键索引外,还额外创建了联合索引idx_name_age_positionDROP TABLE IF EXISTS employees;CREATE TABLE employees ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(24) NOT NULL DEFAULT '' COMMENT '
2022-04-29 17:49:06 952
原创 SQL执行流程与Binlog
MySQL中,一条语句的执行要经过很多个步骤才能完成,MySQL将这些步骤分为两个大的部分:Server层和存储引擎层,其中Server层负责SQL语法解析、优化,然后调用存储引擎的查询接口,而存储引擎只需要提供统一的入口即可。内部组件如下:通过这种图,我们来具体分析MySQL中一条SQL的执行过程。一、Server层Server层主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都
2022-04-28 19:44:20 1380 1
原创 MySQL索引使用准测
SQL语句中使用索引,是需要遵守一些准则的,否则极有可能导致索引失效,这篇文章主要就是介绍索引使用过程的一些注意事项。一、数据准备建立一张员工表:DROP TABLE IF EXISTS employees;CREATE TABLE employees ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(24) NOT NULL DEFAULT '' COMMENT '姓名', age int(11) NOT NULL DEFAULT '
2022-04-27 17:42:07 928 1
原创 Explain使用详解
在日常开发工作中,对于SQL的书写,通常都会尽量让SQL能够使用到表中创建的索引,以此来提高SQL语句的性能。想要参看一个SQL是否会使用索引,可以使用MySQL字段的分析工具Explain,这篇文章重要介绍该工具的使用。一、 简介使用Explain关键字可以模拟优化器执行SQL语句,进而分析查询语句或结构的性能瓶颈。在SQL语句之前增加Explain关键字,MySQL会设置一个标记,执行查询会返回执行计划的信息,而不是执行这条SQL。注:如果from中包含了子查询,仍会执行该子查询,将结果放入到临时
2022-04-27 16:08:48 3481 1
原创 MySQL索引基础
索引作为MySQL最为重要的组成部分,它通过将数据按照一定规则进行排序,形成一种特定的数据结构,从而加速数据的访问效率。一、索引数据结构索引数据结构通常有如下几种选择:二叉树、红黑树、Hash表、B树、B+树,这些数据结构都有各自的特性。二叉树二叉树是最普通的树结构,对结构平衡等都没有特别的实现,新增节点时只是按照已有树结构的排列顺序,比当前节点值大就放在右节点上,比当前节点值小就放在左节点上,通常二叉树的可以有如下结构:
2022-04-26 19:02:14 1481
原创 并发编程中的设计模式
在并发编程的过程中,对于某些特定的问题,一般都有特定的解决方案来处理,就好像是设计模式一样,它们具有通用的模板。可以把这些解决方案称为并发编程中的设计模式。这篇文章结合《Java源码世界》专题中并发工具类以及多线程的相关文章进行总结,形成的一种并发编程的技巧。一、线程终止在多线程开发的时候,经常会用到,在某个线程中,需要去终止另外一个线程,Thread类也提供了终止线程的方法stop(),但在JDK中该方法被标记为@Deprecated,原因就在于该方法做过于暴力。stop()会直接真正杀死进程,如果
2022-03-11 23:27:19 780
原创 高性能内存队列Disruptor
一、简介Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级)。基于Disruptor开发的系统单线程能支撑每秒600万订单,2010年在QCon演讲后,获得了业界关注。2011年,企业应用软件专家Martin Fowler专门撰写长文介绍。同年它还获得了Oracle官方的Duke大奖。目前,包括Apache Storm、Camel、Log4j 2在内的很多知名项目都应用了Disruptor以获取高性能。
2022-03-09 14:27:39 671
原创 CompletableFuture使用详解
一、简介1.1 概述在上一篇文章《CompletionService使用与源码分析》中,已经介绍过了Future的局限性,它没法直接对多个任务进行链式、组合等处理,需要借助并发工具类才能完成,实现逻辑比较复杂。而CompletableFuture是对Future的扩展和增强。CompletableFuture实现了Future接口,并在此基础上进行了丰富的扩展,完美弥补了Future的局限性,同时CompletableFuture实现了对任务编排的能力。借助这项能力,可以轻松地组织不同任务的运行顺序、
2022-03-08 16:38:08 119220 40
原创 CompletionService使用与源码分析
一、Future&FutureTask在《Java线程详解》这篇文章中,介绍了创建一个Java线程的三种方式,其中继承Thread类或实现Runnable接口都可以创建线程,但这两种方法都有一个问题就是:没有返回值,不能获取执行完的结果。因此后面在JDK1.5才新增了一个Callable接口来解决上面的问题,而Future和FutureTask就可以与Callable配合起来使用。而Callable只能在线程池中提交任务使用,且只能在submit()和invokeAnay()以及invokeAl
2022-03-06 18:11:09 9162 9
原创 Fork/Join工作原理解析
一、如何高效利用CPU在介绍Fork/Join框架之前,思考一个问题,在多线程的情况下,如何才能高效的利用CPU,以常用的线程池为例,线程池的线程数设置多少合适?通常调整线程池中的线程数量其核心目的就是为了能够充分的利用CPU和内存资源,从而最大限度的提高程序的性能。在实际工作中,我们可能会根据任务类型的不同而采取不同的策略。按照一个任务执行过程中使用CPU的时间和任务总耗时的比例,可以将任务分为两种:CPU密集型任务和IO密集型任务1.1 任务类型1.1.1 CPU密集型任务CPU密集型任务也称
2022-03-05 12:40:51 1940
原创 BlockingQueue源码分析
一、阻塞队列简介队列常被用来解决生产——消费者问题,Java中定义了Queue接口以及通用的一些抽象方法public interface Queue<E> extends Collection<E> { // 添加一个元素,添加成功返回true,如果队列满了就抛出异常 boolean add(E e); //添加一个元素,添加成功返回true,如果队列满了返回false boolean offer(E e); // 删除并返回队首元素,
2022-03-02 18:56:57 533
空空如也
类成员变量无法引用@value注解修饰的成员变量的值
2021-09-03
TA创建的收藏夹 TA关注的收藏夹
TA关注的人